Files
hera-web/scripts/tiangongStore.test.cjs
T

108 lines
6.6 KiB
JavaScript
Raw Normal View History

const test = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const path = require('node:path')
const vm = require('node:vm')
const ts = require('typescript')
function load(file, deps = {}) {
const exports = {}
vm.runInNewContext(ts.transpileModule(fs.readFileSync(path.join(__dirname, '..', file), 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 } }).outputText, { exports, require: id => deps[id], setTimeout, clearTimeout })
return exports
}
const ritual = load('src/utils/incenseRitual.ts')
const mock = load('src/utils/tiangongMock.ts', { './incenseRitual': ritual })
const { createTiangongStore } = load('src/utils/tiangongStore.ts', { './tiangongMock': mock, './incenseRitual': ritual })
const defer = () => { let resolve, reject; const promise = new Promise((ok, fail) => { resolve = ok; reject = fail }); return { promise, resolve, reject } }
function harness() {
let key = 'account-a', time = 1000, rows = [{ id: 81, name: '财神', holdingId: 726, active: true, incenseCount: 7, days: 3 }]
let loader = async () => rows, offer = async () => ({ id: 99 })
const calls = []
const store = createTiangongStore({ key: () => key, now: () => time, resolve: name => name === '财神' ? 'wealth' : undefined,
load: () => loader(), offer: (...args) => { calls.push(args); return offer(...args) }, dedicate: async (...args) => { calls.push(args); return { id: 100 } } })
return { store, calls, key: value => { key = value }, time: value => { time = value }, rows: value => { rows = value }, load: value => { loader = value }, offer: value => { offer = value } }
}
test('真实状态不预置财神,按后端持有ID提交,后端确认后才计数', async () => {
const h = harness()
assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
await h.store.refresh()
const response = defer(); h.offer(() => response.promise)
const request = h.store.incense('wealth')
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 7)
assert.equal(h.store.snapshot().deities.wealth.lit, false)
assert.equal(h.calls[0][0], 726); assert.equal(h.calls[0][1], 2)
response.resolve({ id: 10 }); await request
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 8)
assert.equal(h.store.snapshot().deities.wealth.incenseUntil, 16000)
})
test('列表图、详情图、介绍独立保存,刷新及切换账号不串用旧素材', async () => {
const h = harness()
h.rows([{ id: 81, name: '财神', holdingId: 726, active: true, incenseCount: 7, days: 3,
iconUrl: '/file/list.png', iconDetailUrl: '/file/detail.png', description: '接口介绍\n第二行' }])
await h.store.refresh()
const first = h.store.snapshot().deities.wealth
assert.equal(first.iconUrl, '/file/list.png'); assert.equal(first.iconDetailUrl, '/file/detail.png')
assert.equal(first.description, '接口介绍\n第二行')
h.rows([{ id: 81, name: '财神', active: false, incenseCount: 0, days: 0,
iconUrl: '/file/new-list.png', iconDetailUrl: '/file/new-detail.png', description: '更新的介绍' }])
await h.store.refresh(true)
const second = h.store.snapshot().deities.wealth
assert.equal(second.unlocked, false); assert.equal(second.iconDetailUrl, '/file/new-detail.png')
assert.equal(second.description, '更新的介绍')
h.key('another-account')
assert.equal(h.store.snapshot().deities.wealth.iconDetailUrl, undefined)
})
test('失败无计数无自动重试;晚到查询不覆盖已确认上香', async () => {
const h = harness(); await h.store.refresh()
h.offer(async () => { throw new Error('网络失败') })
await assert.rejects(h.store.incense('wealth'), /网络失败/)
assert.equal(h.calls.length, 1); assert.equal(h.store.snapshot().deities.wealth.incenseCount, 7)
const read = defer(); h.load(() => read.promise)
const refreshing = h.store.refresh(true)
h.offer(async () => ({ id: 1 })); await h.store.incense('wealth')
read.resolve([{ name: '财神', holdingId: 726, active: true, incenseCount: 7 }]); await refreshing
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 8)
})
test('乱序并发响应逐次累计,不让旧点击缩短最后截止时间', async () => {
const h = harness(); await h.store.refresh()
const a = defer(), b = defer(); let count = 0
h.offer(() => (++count === 1 ? a : b).promise)
const first = h.store.incense('wealth'); h.time(4000); const second = h.store.incense('wealth')
b.resolve({ id: 2 }); assert.equal((await second).startsRound, true)
a.resolve({ id: 1 }); assert.equal((await first).startsRound, false)
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 9)
assert.equal(h.store.snapshot().deities.wealth.incenseUntil, 19000)
h.time(19001); assert.equal(h.store.snapshot().deities.wealth.lit, false)
})
test('写入在途不采纳可能已包含该流水的GET,避免回包后再次加一', async () => {
const h = harness(); await h.store.refresh()
const response = defer(), read = defer()
h.load(() => read.promise)
const refreshing = h.store.refresh(true)
h.offer(() => response.promise); const sending = h.store.incense('wealth')
read.resolve([{ name: '财神', holdingId: 726, active: true, incenseCount: 8 }]); await refreshing
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 7)
await h.store.refresh(true)
response.resolve({ id: 2 }); await sending
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 8)
})
test('切换账号丢弃旧响应,不以Mock兜底;未绑定不可提交', async () => {
const h = harness(); await h.store.refresh()
const response = defer(); h.offer(() => response.promise)
const sending = h.store.incense('wealth')
h.key('account-b'); assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
response.resolve({ id: 10 }); await assert.rejects(sending, /登录状态/)
h.rows([]); await h.store.refresh()
await assert.rejects(h.store.incense('wealth'), /绑定/)
h.load(async () => { throw new Error('未部署') }); await assert.rejects(h.store.refresh(true), /未部署/)
assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
})
test('祈愿和任意姓名回向去空白提交,不携带功德或注册收件人ID', async () => {
const h = harness(); await h.store.refresh()
await h.store.wish('wealth', ' 愿顺遂 ')
await h.store.dedicate('wealth', ' 家人 ', ' 平安 ')
assert.deepEqual(h.calls, [[726, 3, '愿顺遂'], [726, '家人', '平安']])
await assert.rejects(h.store.wish('wealth', ' '), /愿望/)
await assert.rejects(h.store.dedicate('wealth', '', '祝愿'), /回向对象/)
assert.equal(h.calls.length, 2)
})