import assert from 'node:assert/strict' import test from 'node:test' import { readFileSync } from 'node:fs' import { parse } from '@vue/compiler-sfc' import ts from 'typescript' import { ref } from 'vue' function evaluate(file: string, names: string[], b: Record) { const ast = ts.createSourceFile( 'x.ts', parse(readFileSync(new URL(file, import.meta.url), 'utf8')).descriptor.scriptSetup!.content, ts.ScriptTarget.Latest, true ) const text = names .map((name) => { const n = ast.statements.find((n) => ts.isFunctionDeclaration(n) ? n.name?.text === name : ts.isVariableStatement(n) && n.declarationList.declarations.some((d) => d.name.getText(ast) === name) ) assert.ok(n, name) return n.getText(ast) }) .join('\n') return new Function( ...Object.keys(b), ts.transpile(text, { target: ts.ScriptTarget.ESNext }) + ';return {' + names.join(',') + '}' )(...Object.values(b)) } const file = '../src/components/business/pl-paste-recognize-dialog/index.vue' function harness(overrides: any = {}) { const calls: any[] = [], events: any[] = [] const b: any = { ref, pasteSession: ref(0), mobileCarriers: ref([]), mobileCarrierLoading: ref(false), pasteDisposed: ref(false), props: { mode: 'vehicle-bundle', visible: true }, isPageVariant: ref(true), isMobileVariant: ref(true), parsed: ref({}), rawText: ref('车牌:皖QA1023 皖QA102挂'), vehicleForm: { licensePlate: '皖QA1023', trailerNo: '皖QA102挂', loadCapacity: 3 }, driverForm: { personnelName: '', phoneNo: '', idCardNo: '' }, escortForm: { personnelName: '', phoneNo: '', idCardNo: '' }, carrierOptions: ref([]), carrierId: ref(''), conflictRows: ref([]), showVehicleFields: ref(true), submitLoading: ref(false), parseLoading: ref(false), conflictFingerprint: ref(''), currentConflictFingerprint: () => '', ensureCarriers: async () => {}, detectConflicts: async () => {}, pasteRecognizeApi: { commit: async (p: any) => { calls.push(p) return { vehicleId: 'v1' } } }, pickBxData: (x: any) => x, ElMessage: { warning: () => {}, info: () => {}, error: () => {}, success: () => {} }, emit: (...a: any[]) => events.push(a), innerVisible: ref(true), ...overrides } Object.assign(b, evaluate(file, ['isPasteSessionCurrent', 'invalidatePasteSession'], b)) return { ...evaluate(file, ['handleSubmit', 'handleCancel'], b), b, calls, events } } test('optional empty personnel produces null people and correct vehicle ID', async () => { const h = harness() await h.handleSubmit() assert.equal(h.calls[0].driver, null) assert.equal(h.calls[0].escort, null) assert.deepEqual(h.events[0], ['done', { vehicleId: 'v1' }]) }) test('quick create double click commits once', async () => { const h = harness() await Promise.all([h.handleSubmit(), h.handleSubmit()]) assert.equal(h.calls.length, 1) }) test('cancel does not commit; failed generation retains inputs', async () => { const h = harness({ pasteRecognizeApi: { commit: async () => { throw Error('failed') } } }) h.handleCancel() assert.equal(h.calls.length, 0) await h.handleSubmit() assert.equal(h.b.vehicleForm.licensePlate, '皖QA1023') assert.equal( h.events.some((e: any) => e[0] === 'done'), false ) }) for (const action of ['reuse', 'overwrite', 'cancel']) test('conflict ' + action + ' keeps payload choice', async () => { const row = { key: 'vehicle', existingId: 'old', action } const h = harness({ conflictRows: ref([row]) }) await h.handleSubmit() if (action === 'cancel') assert.equal(h.calls.length, 0) else assert.deepEqual(h.calls[0].conflicts, [row]) }) test('edited identity triggers fresh conflict lookup before commit', async () => { const h = harness({ conflictFingerprint: ref('old'), currentConflictFingerprint: () => 'new', conflictRows: ref([{ key: 'vehicle', existingId: 'old', action: 'reuse' }]) }) h.b.detectConflicts = async () => { h.b.conflictRows.value = [{ key: 'vehicle', existingId: 'new', action: 'reuse' }] h.b.conflictFingerprint.value = 'new' return true } const run = evaluate(file, ['handleSubmit'], h.b).handleSubmit await run() assert.equal(h.calls.length, 0) await run() assert.equal(h.calls[0].conflicts[0].existingId, 'new') }) test('actual lookup ignores stale identity response', async () => { let release: any const pending = new Promise((r) => (release = r)) const h = harness({ currentConflictFingerprint: () => h.b.vehicleForm.licensePlate, vehicleApi: { list: () => pending }, personnelApi: { list: async () => ({ list: [] }) }, pickBxPageResult: (x: any) => x }) const lookup = evaluate(file, ['detectConflicts'], h.b).detectConflicts const running = lookup() h.b.vehicleForm.licensePlate = 'changed' release({ list: [{ id: 'old', licensePlate: '皖QA1023' }] }) assert.equal(await running, false) assert.equal(h.b.conflictRows.value.length, 0) }) test('old same-identity lookup cannot overwrite a reopened session conflict', async () => { let release:any const h=harness({ createVehicle:ref(true), PL_PASTE_SAMPLE_TEXT:'', vehicleApi:{list:()=>new Promise(r=>release=r)}, personnelApi:{list:async()=>({list:[]})}, pickBxPageResult:(x:any)=>x }) const f=evaluate(file,['detectConflicts','handleClosed'],h.b) const old=f.detectConflicts();f.handleClosed() h.b.vehicleForm.licensePlate='皖QA1023';h.b.conflictRows.value=[{key:'vehicle',existingId:'new-session-id',action:'reuse'}] release({list:[{id:'old-session-id',licensePlate:'皖QA1023'}]}) await old;assert.equal(h.b.conflictRows.value[0].existingId,'new-session-id') }) for (const reject of [false,true]) test('closed-session commit '+(reject?'failure':'success')+' neither emits nor resets new loading',async()=>{ let settle:any const h=harness({createVehicle:ref(true), PL_PASTE_SAMPLE_TEXT:'',pasteRecognizeApi:{commit:()=>new Promise((yes,no)=>settle=reject?no:yes)}}) const f=evaluate(file,['handleSubmit','handleClosed'],h.b) const running=f.handleSubmit();await new Promise(r=>setTimeout(r,0));f.handleClosed();h.b.submitLoading.value=true settle(reject?Error('old failure'):{vehicleId:'old-vehicle'});await running assert.equal(h.events.length,0);assert.equal(h.b.submitLoading.value,true) }) test('old parse failure does not clear reopened loading or display error',async()=>{ let reject:any;const errors:any[]=[] const h=harness({createVehicle:ref(true),PL_PASTE_SAMPLE_TEXT:'',parsePlCustomerVehicleText:()=>({vehicle:{licensePlate:'皖QA1023'},warnings:[]}),detectConflicts:()=>new Promise((_,no)=>reject=no),ElMessage:{warning:()=>{},error:(value:any)=>errors.push(value)}}) const f=evaluate(file,['handleParse','handleClosed'],h.b);const old=f.handleParse();f.handleClosed();h.b.parseLoading.value=true;reject(Error('old'));await old assert.equal(h.b.parseLoading.value,true);assert.deepEqual(errors,[]) }) test('old carrier search cannot replace new session options or clear its loading',async()=>{ let release:any;const h=harness({createVehicle:ref(true),PL_PASTE_SAMPLE_TEXT:'',mobileCarrierRequest:0,carrierApi:{list:()=>new Promise(r=>release=r)},pickBxList:(value:any)=>value}) const f=evaluate(file,['searchMobileCarriers','handleClosed'],h.b);const old=f.searchMobileCarriers('');f.handleClosed();h.b.mobileCarriers.value=[{id:'new'}];h.b.mobileCarrierLoading.value=true;release([{id:'old'}]);await old assert.equal(h.b.mobileCarriers.value[0].id,'new');assert.equal(h.b.mobileCarrierLoading.value,true) })