89 lines
5.0 KiB
JavaScript
89 lines
5.0 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFile } from 'node:fs/promises'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { dispatchBusinessSnapshot } from './phase4-overseas-dispatch.mjs'
|
|
|
|
const moduleUrl = new URL('./phase4-overseas-dispatch.mjs', import.meta.url)
|
|
const source = await readFile(fileURLToPath(moduleUrl), 'utf8')
|
|
|
|
test('phase4 overseas dispatch module freezes only stable platform query and smart pre-arrange paths', () => {
|
|
for (const token of [
|
|
"const BASE = '/api/platform/v1/last-leg/dispatches'",
|
|
"query(BASE, { page: 1, size: 20 })",
|
|
'`${BASE}/candidates`', '`${BASE}/drafts`', '`${BASE}/drafts/snapshot`',
|
|
'`${BASE}/draft-locks/lock`', '`${BASE}/pre-arrange`', '`${BASE}/draft-locks/release`',
|
|
'`${BASE}/${encodeURIComponent(dispatchNo)}`',
|
|
]) assert.match(source, new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')))
|
|
for (const forbidden of ['/api/pda/', '/outbound', '/delivery', '/depart', '/cancel']) {
|
|
assert.equal(source.includes(forbidden), false, `must exclude ${forbidden}`)
|
|
}
|
|
})
|
|
|
|
test('module uses marker-owned completed PDA pallets and never borrows historical candidates', () => {
|
|
assert.match(source, /fixture\?\.marker !== context\.marker/)
|
|
assert.match(source, /fixture\?\.finalStatus !== 'COMPLETED'/)
|
|
assert.match(source, /fixture\.palletIds\.has\(id\(value\?\.warehousePalletId\)\)/)
|
|
assert.match(source, /id\(value\?\.overseasWarehouseId\) === id\(fixture\.overseasWarehouseId\)/)
|
|
assert.doesNotMatch(source, /candidates\[0\]/)
|
|
})
|
|
|
|
test('ordinary dispatch selects one current-run pallet per destination for multi-FBA delivery proof', () => {
|
|
assert.match(source, /const candidatesByDestination = new Map\(\)/)
|
|
assert.match(source, /destinationWarehouseCode \|\| value\?\.fbaWarehouseCode/)
|
|
assert.match(source, /selectedCandidates\.length >= 2/)
|
|
assert.match(source, /planPalletIds, route: `\$\{context\.marker\}-ROUTE`/)
|
|
assert.match(source, /Number\(arranged\.data\?\.palletCount\) === planPalletIds\.length/)
|
|
})
|
|
|
|
test('module proves draft idempotency, lock isolation, editable pre-arrange replay and readback', () => {
|
|
assert.match(source, /相同草稿快照重复保存/)
|
|
assert.match(source, /同草稿重复锁定托盘幂等成功/)
|
|
assert.match(source, /其他草稿锁定同一托盘返回A0409/)
|
|
assert.match(source, /出库前同草稿重复预排复用原排车且业务快照不漂移/)
|
|
assert.match(source, /重复释放草稿幂等成功/)
|
|
assert.match(source, /排车详情按记录自身客户范围加载托盘明细/)
|
|
assert.match(source, /response\?\.http === 409.*codeOf\(response\) === 'A0409'/s)
|
|
})
|
|
|
|
test('module does not invent optimistic version or idempotency headers absent from DispatchRequests', () => {
|
|
assert.doesNotMatch(source, /expectedVersion|recordVersion|Idempotency-Key/)
|
|
assert.match(source, /PENDING_DEPARTURE/)
|
|
assert.match(source, /data == null/)
|
|
})
|
|
|
|
test('module records the marker-owned dispatch without attempting excluded cleanup actions', () => {
|
|
assert.match(source, /createdResources\.phase4OverseasDispatch/)
|
|
assert.match(source, /dispatchNo = dispatchNo/)
|
|
assert.match(source, /finalStatus = arranged\.data\?\.status/)
|
|
assert.match(source, /PENDING_DEPARTURE dispatch is retained as marker-owned acceptance evidence/)
|
|
})
|
|
|
|
test('module prefers marker-owned relabel pallets and proves only new FBA carton marks are frozen', () => {
|
|
assert.match(source, /phase4OverseasRelabel/)
|
|
assert.match(source, /sourceStage === 'RELABEL'/)
|
|
assert.match(source, /relabel\.targetPalletIds\.includes/)
|
|
assert.match(source, /relabelCartonMarks/)
|
|
assert.match(source, /!String\(value\?\.cartonMarks \|\| ''\)\.trim\(\)/)
|
|
assert.match(source, /relabelNo: relabel\.relabelNo/)
|
|
})
|
|
|
|
test('relabel settlement follows pre-arrange and does not replace the ordinary dispatch lifecycle', () => {
|
|
assert.match(source, /await runRelabelDispatch\(context, relabel\)[\s\S]*if \(relabel.dispatchNo\) await settleRelabelFulfillment\(context, relabel\)/)
|
|
const branch = source.slice(source.indexOf('const relabel = context.createdResources'), source.indexOf('const fixture = markerFixture(context)', source.indexOf('const relabel = context.createdResources')))
|
|
assert.doesNotMatch(branch, /\breturn\b/)
|
|
assert.match(source, /Object.assign\(relabel, \{/)
|
|
})
|
|
|
|
test('dispatch replay snapshot ignores regenerated item ids but detects business drift', () => {
|
|
const a = { id: '1', dispatchNo: 'DS-1', status: 'PENDING_DEPARTURE', packageCount: 2,
|
|
palletCount: 1, items: [{ id: '10', planPalletId: '20', warehousePalletId: '30', packageCount: 2 }] }
|
|
const replay = { ...a, items: [{ ...a.items[0], id: '11' }] }
|
|
assert.equal(dispatchBusinessSnapshot(a), dispatchBusinessSnapshot(replay))
|
|
for (const changed of [{ ...replay, id: '2' }, { ...replay, packageCount: 4 },
|
|
{ ...replay, items: [{ ...a.items[0], warehousePalletId: '31' }] }]) {
|
|
assert.notEqual(dispatchBusinessSnapshot(a), dispatchBusinessSnapshot(changed))
|
|
}
|
|
assert.doesNotMatch(source, /item\?\.cartonMarks/)
|
|
})
|