71 lines
3.3 KiB
TypeScript
71 lines
3.3 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
import { parse } from '@vue/compiler-sfc'
|
|
import ts from 'typescript'
|
|
|
|
function harness(arrange = false) {
|
|
const script = parse(readFileSync(new URL('../src/components/business/pl-plan-quota-dialog/index.vue', import.meta.url), 'utf8')).descriptor.scriptSetup!.content
|
|
const ast = ts.createSourceFile('quota.ts', script, ts.ScriptTarget.Latest, true)
|
|
const method = ast.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === 'accept')!.getText(ast)
|
|
let finish!: () => void
|
|
const pending = new Promise<void>(r => { finish = r })
|
|
const callbacks: any[] = []
|
|
const state: any = {
|
|
plan: { value: { planId: 'a' } }, busy: { value: false }, visible: { value: true },
|
|
forArrange: { value: arrange }, forSupplement: { value: false },
|
|
result: { value: { status: 'available' } },
|
|
preview: () => pending, payload: () => ({ purchaseCertIds: ['p'] }),
|
|
planQuotaApi: { save: () => pending }, ElMessage: { success() {}, warning() {} }
|
|
}
|
|
const js = ts.transpileModule(`let epoch=0; let resolve=(v)=>callbacks.push(['old',v]);${method};return {run:accept,change:()=>{epoch++;plan.value={planId:'b'};busy.value=true;resolve=(v)=>callbacks.push(['new',v])}}`, {compilerOptions:{target:ts.ScriptTarget.ES2022}}).outputText
|
|
const actions = new Function(...Object.keys(state), 'callbacks', js)(...Object.values(state), callbacks)
|
|
return { ...actions, state, callbacks, finish }
|
|
}
|
|
for (const arrange of [false, true]) test(`stale ${arrange ? 'preview' : 'save'} cannot resolve or close the next session`, async () => {
|
|
const h = harness(arrange), task = h.run()
|
|
h.change(); h.finish(); await task
|
|
assert.deepEqual(h.callbacks, [])
|
|
assert.equal(h.state.visible.value, true)
|
|
assert.equal(h.state.busy.value, true)
|
|
})
|
|
|
|
for (const methodName of ['preview', 'loadContext'])
|
|
test(`${methodName} ignores a result when configuration changes in flight`, async () => {
|
|
const script = parse(
|
|
readFileSync(
|
|
new URL('../src/components/business/pl-plan-quota-dialog/index.vue', import.meta.url),
|
|
'utf8'
|
|
)
|
|
).descriptor.scriptSetup!.content
|
|
const ast = ts.createSourceFile('quota.ts', script, ts.ScriptTarget.Latest, true)
|
|
const method = ast.statements
|
|
.find((n) => ts.isFunctionDeclaration(n) && n.name?.text === methodName)!
|
|
.getText(ast)
|
|
let finish!: (value: any) => void
|
|
const pending = new Promise<any>((r) => {
|
|
finish = r
|
|
})
|
|
const state: any = {
|
|
plan: { value: { planId: 'a' } },
|
|
busy: { value: false },
|
|
result: { value: undefined },
|
|
context: { value: undefined },
|
|
payload: () => ({}),
|
|
previewVehicle: {},
|
|
planQuotaApi: { preview: () => pending, context: () => pending }
|
|
}
|
|
const js = ts.transpileModule(
|
|
`let epoch=0,revision=0;${method};return {run:${methodName},change:()=>revision++}`,
|
|
{ compilerOptions: { target: ts.ScriptTarget.ES2022 } }
|
|
).outputText
|
|
const actions = new Function(...Object.keys(state), js)(...Object.values(state))
|
|
const task = actions.run()
|
|
actions.change()
|
|
finish({ status: 'available', sourceFingerprint: 'old' })
|
|
await task
|
|
assert.equal(state.result.value, undefined)
|
|
assert.equal(state.context.value, undefined)
|
|
assert.equal(state.busy.value, false)
|
|
})
|