| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- 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<string, any>) {
- 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)
- })
|