Files

51 lines
4.1 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import vm from 'node:vm'
import { getDispatchHandoverStatus, normalizeHandoverStatus } from '../src/api/trip-handover.js'
import { session } from '../src/stores/session.js'
const wire = () => ({ dispatchNo: 'PC-ONE', tripNo: 'TR-ONE', tripStatus: 'IN_TRANSIT', tripRecordVersion: '90071992547409931',
originalDeparture: { vehiclePlate: 'ORIGINAL', driverName: '原司机' },
deliveries: [{ deliveryNo: 'DL-DONE', status: 'DELIVERED', packages: '10', remainingPackages: 0, terminalAt: '2026-10-03T01:00:00Z', transport: { vehiclePlate: 'ORIGINAL', driverName: '原司机' } },
{ deliveryNo: 'DL-PENDING', status: 'WAIT_DELIVERY', packages: 20, remainingPackages: 16, terminalAt: null, transport: { vehiclePlate: 'NEW', driverName: '接替司机' } }], latestHandover: null })
test('PDA query stays a GET in the dedicated namespace and never supplies customer or warehouse', async () => {
const calls = []; session.apiBase = '/gateway-api'; session.token = 'test-token'
globalThis.uni = { request(options) { calls.push(options); options.success({ statusCode: 200, data: { code: '200', data: wire() }, header: {} }) } }
const result = await getDispatchHandoverStatus('PC-ONE')
assert.equal(calls.length, 1); assert.equal(calls[0].method, 'GET'); assert.match(calls[0].url, /\/pda\/v1\/last-leg\/dispatches\/PC-ONE\/handover-status$/)
assert.ok(!calls[0].data?.customerId); assert.ok(!calls[0].data?.warehouseId)
assert.equal(result.tripRecordVersion, '90071992547409931'); assert.equal(result.deliveries[0].transport.vehiclePlate, 'ORIGINAL'); assert.equal(result.deliveries[1].transport.vehiclePlate, 'NEW')
})
test('normalization exposes only business references and does not replace missing fields with internal IDs', () => {
const data = wire(); data.customerId = 'secret-customer'; data.originalDeparture = { vehicleId: 'secret-vehicle' }; data.deliveries[0].id = 'secret-id'
const value = normalizeHandoverStatus(data)
assert.doesNotMatch(JSON.stringify(value), /secret-/); assert.equal(value.originalDeparture.vehiclePlate, '')
assert.equal(value.deliveries[0].packages, 10)
assert.equal(value.deliveries[1].remainingPackages, 16)
for (const remainingPackages of [null, '', -1, 21, '1.5']) assert.throws(() => normalizeHandoverStatus({ ...data, deliveries: [{ ...data.deliveries[1], remainingPackages }] }), /剩余箱数无效/)
for (const packages of [null, '', -1, 0, '1.5']) assert.throws(() => normalizeHandoverStatus({ ...data, deliveries: [{ ...data.deliveries[0], packages }] }), /箱数无效/)
})
test('a response for another dispatch is rejected', async () => {
session.apiBase = '/gateway-api'; session.token = 'test-token'
globalThis.uni = { request(options) { options.success({ statusCode: 200, data: { code: '200', data: wire() }, header: {} }) } }
await assert.rejects(getDispatchHandoverStatus('PC-OTHER'), /不属于当前排车/)
})
test('the component ignores stale responses after switching task and has no write commands', async () => {
const file = await readFile(new URL('../src/components/DispatchHandoverStatus.vue', import.meta.url), 'utf8')
const pending = []
const context = { getDispatchHandoverStatus: () => new Promise(resolve => pending.push(resolve)), toDispatchError: error => ({ message: error.message }) }
const source = file.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^import .*$/gm, '').replace('export default', 'component =')
vm.runInNewContext(source, context)
const component = context.component, state = { ...component.data(), dispatchNo: 'PC-OLD' }
const first = component.methods.load.call(state)
state.dispatchNo = 'PC-NEW'; const second = component.methods.load.call(state)
pending[1]({ dispatchNo: 'PC-NEW' }); await second
pending[0]({ dispatchNo: 'PC-OLD' }); await first
assert.equal(state.status.dispatchNo, 'PC-NEW')
assert.doesNotMatch(file, /confirmTripHandover|departDispatch|pickDispatchItem|POST/)
const page = await readFile(new URL('../src/pages/dispatch/dispatch.vue', import.meta.url), 'utf8')
assert.match(page, /DispatchHandoverStatus v-if="departed" :dispatch-no="current.dispatchNo"/)
})