Files
shanxia2.0/web-admin/scripts/quota-config-submission.test.ts
T
wuzilongandCursor 8e9536332a feat: 保存运输证件、报销付款和开发流程的当前实现。
补齐证书齐备、证件折算、移动用证和合同绑定,并带上报销批量发放、付款备注以及个人开发流程升级,便于继续讨论已安排计划的调整规则。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 21:42:33 +08:00

98 lines
5.2 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)
})
test('existing usage table exposes each certificate quantity unit alongside reserved and used values', () => {
const template = parse(readFileSync(new URL('../src/components/business/pl-plan-quota-dialog/index.vue', import.meta.url), 'utf8')).descriptor.template!.content
const usageTable = template.slice(template.indexOf(':data="plan.usages"'), template.indexOf('</section>', template.indexOf(':data="plan.usages"')))
const columns = [...usageTable.matchAll(/prop="([^"]+)"/g)].map(match => match[1])
const visible = [{ certNoSnapshot:'BUY', reservedQty:100, usedQty:20, quantityUnit:'吨' }, { certNoSnapshot:'MOVE', reservedQty:100000, usedQty:20000, quantityUnit:'千克' }].map(row => Object.fromEntries(columns.map(key => [key, row[key as keyof typeof row]])))
assert.equal(visible[0].quantityUnit, '吨')
assert.equal(visible[1].quantityUnit, '千克')
})
test('viewing certificate usage lists every stop and leaves opposite pairing to submission', () => {
const dialog = parse(
readFileSync(new URL('../src/components/business/pl-plan-quota-dialog/index.vue', import.meta.url), 'utf8')
).descriptor.template!.content
const mobile = parse(
readFileSync(new URL('../src/views/m/pl/plan-cert/CertFacePanel.vue', import.meta.url), 'utf8')
).descriptor.template!.content
const heading = dialog.indexOf('全部装送段用证需求')
const boundary = dialog.indexOf('<section v-else', heading)
const view = dialog.slice(heading, boundary)
assert.equal(dialog.includes('v-if="viewOnly && isPerStop"'), false)
assert.match(view, /:data="plan\.sourceOptions"/)
assert.doesNotMatch(view, /原口径|勾选对应另一侧/)
assert.match(dialog.slice(boundary), /勾选对应另一侧产品行(必选)/)
assert.doesNotMatch(mobile, /原口径:唯一计量侧与装送配对|勾选对应另一侧产品行/)
assert.match(mobile, /v-for="row in sourceOptions"/)
})