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() { const script = parse(readFileSync(new URL('../src/components/business/pl-plan-archive-dialog/index.vue', import.meta.url), 'utf8')).descriptor.scriptSetup!.content const ast = ts.createSourceFile('archive.ts', script, ts.ScriptTarget.Latest, true) const methods = ast.statements.filter(n => ts.isFunctionDeclaration(n) && ['handleSubmit', 'submitArchiveWithOverageConfirm'].includes(n.name?.text || '')).map(n => n.getText(ast)).join('\n') const calls: any[] = [] let resolveQuota: (value: any) => void = () => {} let outcome: any = {} const body = { products: [{ id: 'source-a', actualQty: 18 }] } const state: any = { props: { planId: 'a' }, innerVisible: { value: true }, submitLoading: { value: false }, canSubmitStopArchive: { value: true }, loadProductRows: { value: [] }, deliveryBlocks: { value: [] }, productRows: { value: [{ isToxic: 1 }] }, formData: { hasFreight: 0 }, plan: { value: {} }, isAdjustMode: { value: false }, quotaSettlementDialog: { value: { open: () => new Promise(resolve => { resolveQuota = resolve }) } }, syncSegmentBrandTotals() {}, syncMultiStopBrandActualQty() {}, validateStopArchiveRows() {}, validateSegmentBrandRows() {}, validatePlanLevelBrandTotals() {}, hasFeedbackAttachmentUploading: () => false, buildArchiveBody: () => body, ElMessage: { warning() {}, success() {}, error() {} }, ElMessageBox: { alert: async () => {} }, tabsRef: { value: null }, emit() {}, pickBxData: (v: any) => v, extractArchiveLineOverageDetail: () => null, applyArchiveOverageHighlight() {}, showArchiveLineOverageConfirm: async () => false, planApi: { archive: async (id: string, data: any) => { calls.push({ id, data }); if(outcome instanceof Error) throw outcome; return outcome } } } const js = ts.transpileModule(`let archiveSession=0; let quotaArchiveAttempt={signature:'',id:''};${methods}; return {run:handleSubmit,submit:submitArchiveWithOverageConfirm,invalidate:()=>archiveSession++}`, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.None } }).outputText const actions = new Function(...Object.keys(state), js)(...Object.values(state)) return { state, calls, body, ...actions, resolveQuota: (v: any) => resolveQuota(v), outcome: (v: any) => { outcome=v } } } test('waiting quota response cannot submit a subsequently opened plan', async () => { const h = harness(); const task = h.run() assert.equal(h.state.submitLoading.value, true) h.state.props.planId = 'b'; h.invalidate(); h.resolveQuota({ quotaManualActuals: [] }) await task assert.deepEqual(h.calls, []) }) test('quota wait preserves the clicked plan and frozen actual quantities', async () => { const h = harness(); const task = h.run() h.body.products[0].actualQty = 999 h.resolveQuota({ quotaManualActuals: [] }); await task assert.equal(h.calls[0].id, 'a') assert.equal(h.calls[0].data.products[0].actualQty, 18) }) test('committed quota exception starts a new operation; unknown transport failure reuses operation', async () => { const h = harness(); h.outcome({ quotaSettlementError: '余额不足' }) await assert.rejects(h.submit('a', h.body, () => true)) h.outcome({}); await h.submit('a', h.body, () => true) assert.notEqual(h.calls[0].data.operationId, h.calls[1].data.operationId) h.outcome(new Error('network')); await assert.rejects(h.submit('a', h.body, () => true)) h.outcome({}); await h.submit('a', h.body, () => true) assert.equal(h.calls[2].data.operationId, h.calls[3].data.operationId) })