2026-10-20 15:48:38 +08:00
import test from 'node:test'
import assert from 'node:assert/strict'
2026-10-21 14:30:41 +08:00
import { feeCents , assertDualDestinationFixture , extensionMatrix , verifyLoadingReplayRace , executeFirstLoadingRace , assertBolPages , assertConfirmedRelabelCancellation } from './dispatch-workflow-extension-acceptance.mjs'
2026-10-20 15:48:38 +08:00
import { parseExtensionArguments , runDispatchExtensions } from '../dispatch-workflow-extensions-test-env.mjs'
test ( 'default plan imports without credentials/network and keeps all unexecuted gaps explicit' , async () => {
const plan = await runDispatchExtensions ( parseExtensionArguments ([]), {})
assert . equal ( plan . execute , false ); assert . equal ( plan . matrix . length , 5 )
2026-10-20 16:45:04 +08:00
assert . equal ( extensionMatrix . find ( row => row . scenario === 'relabel' ). readiness , 'READY_FORMAL_THREE_BOX_RECEIPT' )
2026-10-20 15:48:38 +08:00
})
test ( 'execution requires fresh explicit TEST scope and declared synthetic load, never coerces a plan' , () => {
const args = [ '--execute' , '--environment' , 'TEST' , '--run-id' , 'EXT1' , '--scenario' , 'dual-destination' , '--warehouse-id' , '10' ,
'--destination-warehouse-id' , '20' , '--pda-env-file' , 'private.env' , '--synthetic-pallet-spaces' , '1' ]
assert . equal ( parseExtensionArguments ( args ). execute , true )
2026-10-20 16:45:04 +08:00
for ( const [ from , to ] of [[ 'TEST' , 'DEV' ], [ 'EXT1' , 'plan' ], [ 'dual-destination' , 'unsupported' ], [ '10' , '' ], [ '1' , '0' ]])
2026-10-20 15:48:38 +08:00
assert . throws (() => parseExtensionArguments ( args . map ( value => value === from ? to : value )))
assert . throws (() => parseExtensionArguments ([... args , '--execute' ]))
})
test ( 'terminal continuation requires an explicit original report hash and is never an implicit replay' , () => {
assert . throws (() => parseExtensionArguments ([ '--scenario' , 'review-terminal' ]))
assert . throws (() => parseExtensionArguments ([ '--resume-report' , 'reports/old/report.json' ]))
const config = parseExtensionArguments ([ '--execute' , '--environment' , 'TEST' , '--run-id' , 'EXTCLOSE1' , '--scenario' , 'review-terminal' ,
'--warehouse-id' , '10' , '--destination-warehouse-id' , '20' , '--pda-env-file' , 'private.env' , '--synthetic-pallet-spaces' , '1' ,
'--resume-report' , 'reports/current/report.json' , '--resume-report-sha256' , 'a' . repeat ( 64 )])
assert . equal ( config . scenario , 'review-terminal' ); assert . equal ( config . resumeReportSha256 , 'a' . repeat ( 64 ))
})
test ( 'dual destination proof rejects reused customer, collapsed destination and missing route stop' , () => {
const fixture = { members : [{ customerId : 'A' , destination : { key : 'FBA:ONE' }, receiptVerified : true },
{ customerId : 'B' , destination : { key : 'FBA:TWO' }, receiptVerified : true }],
tripProof : { stops : [{}, { destinationKey : 'FBA:ONE' }, { destinationKey : 'FBA:TWO' }] } }
assert . doesNotThrow (() => assertDualDestinationFixture ( fixture ))
for ( const mutate of [ f => { f . members [ 1 ]. customerId = 'A' }, f => { f . members [ 1 ]. destination . key = 'FBA:ONE' },
f => { f . tripProof . stops . pop () }]) { const bad = structuredClone ( fixture ); mutate ( bad ); assert . throws (() => assertDualDestinationFixture ( bad )) }
})
test ( 'fee conservation uses integer cents and rejects unsafe, negative or overprecision amounts' , () => {
assert . equal ( feeCents ( '31.25' ), 3125 ); assert . equal ( feeCents ( 47.75 ), 4775 )
for ( const value of [ null , false , - 1 , '1e2' , '0.001' , Number . MAX_SAFE_INTEGER ]) assert . throws (() => feeCents ( value ))
})
for ( const unknown of [ false , true ]) test ( `bounded two-actor race ${ unknown ? 'preserves unknown result and stops' : 'starts both requests before either returns and conserves inventory' } ` , async () => {
const fixture = { dispatchNo : 'OWN' , tripNo : 'TRIP' , warehouseId : 'W' , pdaToken : 'OWN_PDA_TOKEN' , members : [{ customerId : 'A' }, { customerId : 'B' }] }
const context = { marker : 'CURRENT' , createdResources : { dispatchWorkflowCompetition : { status : 'CHECKING' } },
checkpoint : async () => {}, assert : () => {} }
const acknowledgement = { recordVersion : '8' , result : { confirmedLoad : { pallets : [ 'P1' , 'P2' ] } } }
const body = { recordVersion : '7' , idempotencyKey : 'ORIGINAL' , measurements : [ 'P1' , 'P2' ] }, requests = [], waiting = []
const send = async ( method , path , payload , token ) => {
requests . push ({ method , path , payload : structuredClone ( payload ), token })
if ( method === 'GET' ) return { http : 200 , body : { code : '200' , data : { immutable : path } } }
return new Promise (( resolve , reject ) => {
waiting . push ({ resolve , reject , token })
if ( waiting . length === 2 ) for ( const entry of waiting ) {
if ( entry . token ) entry . resolve ({ http : 200 , body : { code : '200' , data : { ... acknowledgement , replayed : true } } })
else if ( unknown ) entry . reject ( Error ( 'Unknown write outcome; preserve original key' ))
else entry . resolve ({ http : 200 , body : { code : 'A0403' , message : '该请求标识不属于当前操作员' } })
}
})
}
const execute = () => verifyLoadingReplayRace ( context , fixture , { readInventory : async scope => ({ ... scope , available : 0 , picked : 1 }) }, send , body , acknowledgement )
if ( unknown ) await assert . rejects ( execute (), /Unknown write outcome/ )
else await execute ()
assert . equal ( waiting . length , 2 )
assert . equal ( requests . filter ( row => row . method === 'POST' ). length , 2 )
assert ( requests . filter ( row => row . method === 'POST' ). every ( row => JSON . stringify ( row . payload ) === JSON . stringify ( body )))
const proof = context . createdResources . dispatchWorkflowCompetition . loadingReplayRace
assert . equal ( proof . status , unknown ? 'UNKNOWN_RESULT' : 'VERIFIED' )
assert . equal ( proof . firstExecutionRace , 'NOT_TESTED' )
if ( ! unknown ) assert . deepEqual ( proof . before , proof . after )
})
test ( 'BOL PDF evidence enforces empty/same/different appointment grouping and actual quantity conservation' , () => {
const fixture = { members : [{ palletNo : 'PALLET_A' , incomingNo : 'PALLET_A' }, { palletNo : 'PALLET_B' , incomingNo : 'PALLET_B' }] }
const pdf = ( isa , pallets , total ) => `BILL OF LADING\nISA #: ${ isa } \n ${ pallets . join ( '\n' ) } \n总箱数 / Total CTNS:\n ${ total } \nDriver signature`
assert . equal ( assertBolPages ([ pdf ( '' , [ 'PALLET_A' , 'PALLET_B' ], 2 )], fixture , { appointments : [] }, 'bol-empty' ). totalPackages , 2 )
assert . equal ( assertBolPages ([ pdf ( 'ISA1' , [ 'PALLET_A' , 'PALLET_B' ], 2 )], fixture ,
{ appointments : [{ data : { confirmationNo : 'ISA1' } }] }, 'bol-same' ). pageCount , 1 )
const appointments = { appointments : [{ data : { confirmationNo : 'ISA1' } }, { data : { confirmationNo : 'ISA2' } }] }
const pages = [ pdf ( 'ISA1' , [ 'PALLET_A' ], 1 ), pdf ( 'ISA2' , [ 'PALLET_B' ], 1 )]
assert . equal ( assertBolPages ( pages , fixture , appointments , 'bol-different' ). pageCount , 2 )
for ( const bad of [[ pdf ( 'ISA1' , [ 'PALLET_A' ], 2 ), pdf ( 'ISA2' , [ 'PALLET_B' ], 2 )],
[ pdf ( 'ISA1' , [ 'PALLET_A' , 'PALLET_B' ], 1 ), pdf ( 'ISA2' , [ 'PALLET_B' ], 1 )],
[ pdf ( 'ISA1' , [ 'PALLET_A' ], 1 ), pdf ( 'ISA1' , [ 'PALLET_B' ], 1 )]])
assert . throws (() => assertBolPages ( bad , fixture , appointments , 'bol-different' ))
})
2026-10-20 16:45:04 +08:00
test ( 'confirmed relabel cancellation conserves customer-confirmed results, method and full inventory while clearing only outbound association' , () => {
const before = { application : { relabelNo : 'RL-OWN' , customerConfirmedAt : '2026-10-20T15:00:00' , status : 'READY_FOR_OUTBOUND' ,
deliveryMethod : 'PICKUP' , fulfillmentStatus : 'OUTBOUND_CREATED' , outboundOrderNo : 'OB-OWN' }, items : [{ id : 'I' , fbaCartonMark : 'NEW' , processedPackages : 1 }] }
const after = structuredClone ( before ); after . application . outboundOrderNo = null ; after . application . fulfillmentStatus = 'WAIT_OUTBOUND_CREATION'
const outbound = { outbound : { outboundNo : 'OB-OWN' , status : 'CANCELLED' } }, stock = { positions : [{ held : 1 , available : 0 }], ledger : [{ immutable : 1 }] }
assert . doesNotThrow (() => assertConfirmedRelabelCancellation ( before , after , outbound , stock , structuredClone ( stock )))
for ( const mutate of [ a => { a . application . customerConfirmedAt = null }, a => { a . application . status = 'CANCELLED' },
a => { a . application . deliveryMethod = 'TRUCK' }, a => { a . application . outboundOrderNo = 'OB-OWN' }, a => { a . items [ 0 ]. processedPackages = 0 }]) {
const bad = structuredClone ( after ); mutate ( bad )
assert . throws (() => assertConfirmedRelabelCancellation ( before , bad , outbound , stock , stock ))
}
assert . throws (() => assertConfirmedRelabelCancellation ( before , after , outbound , stock , { ... stock , ledger : [] }))
})
for ( const winner of [ 'PDA' , 'ADMIN' ]) test ( `first valid loading CAS race records ${ winner } winner and preserves the actual PDA receipt` , async () => {
const context = { marker : 'CURRENT' , createdResources : { dispatchWorkflowCompetition : { status : 'CHECKING' } }, checkpoint : async () => {}, assert : () => {} }
const fixture = { dispatchNo : 'OWN' , tripNo : 'TRIP' , warehouseId : 'W' , pdaToken : 'OWN_PDA' , members : [{ customerId : 'A' }, { customerId : 'B' }] }
const body = { recordVersion : '7' , idempotencyKey : 'ORIGINAL_PDA' , manifestHash : 'ACTUAL_HASH' }
2026-10-21 14:30:41 +08:00
const success = { http : 200 , body : { code : '200' , data : { stage : 'DELIVERING' , recordVersion : '8' , result : { confirmedLoad : { manifestHash : 'ACTUAL_HASH' } } } } }
2026-10-20 16:45:04 +08:00
const rejected = { http : 200 , body : { code : 'A0409' } }, pending = []; let completed = false
const send = async ( method , path , payload , token ) => {
2026-10-21 14:30:41 +08:00
if ( method === 'GET' ) return { http : 200 , body : { code : '200' , data : { stage : completed ? 'DELIVERING' : 'LOADING' ,
2026-10-20 16:45:04 +08:00
recordVersion : completed ? '8' : '7' , counts : { packageCount : 2 , pickedPackageCount : 2 } } } }
return new Promise ( resolve => {
pending . push ({ resolve , token , payload })
if ( pending . length === 2 ) { completed = true ; for ( const request of pending ) request . resolve (( request . token ? 'PDA' : 'ADMIN' ) === winner ? success : rejected ) }
})
}
const outcome = await executeFirstLoadingRace ( context , fixture , { readInventory : async scope => ({ ... scope , picked : 1 }) }, send , body )
assert . equal ( pending . length , 2 ); assert . notEqual ( pending [ 0 ]. payload . idempotencyKey , pending [ 1 ]. payload . idempotencyKey )
assert . equal ( context . createdResources . dispatchWorkflowCompetition . firstLoadingRace . winner , winner )
assert . equal ( outcome . pdaResponse , winner === 'PDA' ? success : rejected )
assert . equal ( Boolean ( outcome . error ), winner === 'ADMIN' )
})