Files
baiyue-firstleg/scripts/admin-test-env-modules/looseboard-pool-binding-contract.test.mjs

103 lines
6.0 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { bindLooseboardDemand } from './looseboard-pool-binding.mjs'
// 有状态模拟保留原单与独立询价,重放返回原响应,故障必须在后续写入前停止。
function fixture(fault = '') {
const demand = { marker: 'fixture', orderNo: 'LB-1', customerId: '101', version: 2, finalStatus: 'PENDING_ACCEPTANCE' }
const tripProof = { tripNo: 'TR-1', warehouseId: '42', looseboardOffer: { marker: 'fixture', offerNo: 'OF-1' } }
const offer = { offerNo: 'OF-1', tripNo: 'TR-1', warehouseId: '42', status: 'OPEN', tripRecordVersion: 1, recordVersion: 0,
canCreateInquiry: true, canConfirm: true, capacityKnown: true,
destinations: [{ destinationKey: 'FBA:TEST', remaining: { palletSpaces: fault === 'capacity' ? 0 : 4, weightKg: 400, volumeCbm: 4 } }] }
const original = { remark: 'fixture-original', summary: { ...demand, status: 'PENDING_ACCEPTANCE', estimatedPalletCount: 2,
packageCount: 3, totalWeightKg: 80, totalVolumeCbm: 1.8, productName: 'TEST', currency: 'USD', originContactName: 'TEST', originContactPhone: '19900000000' } }
let created, confirmed, writes = 0
const calls = [], snapshots = []
const context = { marker: 'fixture', createdResources: { phase4OverseasBusiness: { looseboard: demand }, fleetTrips: [tripProof] },
assert(_m, name, _r, ok) { assert.ok(ok, name) }, apiSuccess() {},
async checkpoint() {
if (fault === 'disk') throw Error('disk unavailable')
snapshots.push(structuredClone(demand.poolBinding))
},
async request(method, path, body) {
calls.push({ method, path, body: structuredClone(body) })
if (method === 'POST') writes += 1
let data
if (path.includes('/local-looseboard-orders/')) {
data = structuredClone(original)
if (fault === 'customer') data.summary.customerId = '102'
if (confirmed) {
data.summary.status = 'WAITING_INBOUND'; data.summary.version += 1
data.summary.fleetArrangement = { businessOrderNo: 'LB-1', bookingNo: 'BK-1', tripNo: 'TR-1' }
if (fault === 'binding') data.summary.fleetArrangement.tripNo = 'OTHER'
}
} else if (method === 'GET' && path.endsWith('/OF-1')) data = { offer }
else if (method === 'GET' && path.endsWith('/BK-1')) data = created.inquiry
else if (method === 'POST' && path.endsWith('/OF-1/inquiries')) {
assert.equal(body.sourceOrderNo, 'LB-1'); assert.equal(Number(body.sourceOrderVersion), 2)
assert.equal(body.customerId, '101'); assert.equal(body.expectedPalletCount, 2)
assert.equal(body.cargo.packageCount, 3)
if (fault === 'network') return { http: 0 }
if (!created) {
created = { inquiry: { ...body, offerNo: 'OF-1', tripNo: 'TR-1', bookingNo: 'BK-1', status: 'DRAFT', recordVersion: 0 }, offer }
data = created
} else {
data = { ...structuredClone(created), replayed: true }
if (fault === 'replay') data.inquiry.bookingNo = 'BK-2'
}
} else if (method === 'POST' && path.endsWith('/BK-1/confirm')) {
if (!confirmed) {
confirmed = { inquiry: { ...created.inquiry, status: 'CONFIRMED', recordVersion: 1, agreedAmount: fault === 'price' ? 25 : 50,
businessOrderNo: fault === 'new order' ? 'LB-2' : 'LB-1' }, offer }
data = confirmed
} else data = { ...confirmed, replayed: true }
} else throw Error(`Unexpected ${method} ${path}`)
return { http: 200, body: { code: '200', data: structuredClone(data) }, requestId: 'request', traceId: 'trace' }
} }
return { context, args: { demand, tripProof, offerNo: 'OF-1', destinationKey: 'FBA:TEST', unitPrice: 25 }, calls, snapshots, writes: () => writes }
}
test('pool binding preserves original demand and confirms only one commercial order', async () => {
const f = fixture()
const proof = await bindLooseboardDemand(f.context, f.args)
assert.equal(proof.status, 'CONFIRMED_ORIGINAL_ORDER')
assert.equal(f.args.demand.finalStatus, 'WAITING_INBOUND')
assert.equal(f.writes(), 4)
assert.equal(f.snapshots.at(-1).status, 'CONFIRMED_ORIGINAL_ORDER')
await assert.rejects(bindLooseboardDemand(f.context, f.args), /本轮原单/)
assert.equal(f.writes(), 4)
})
for (const native of [true, false]) test(`native Long inquiry versions remain bounded: ${native ? 'encoded strings' : 'invalid empty value'}`, async () => {
const f = fixture()
// 生产 fixture 已将版本规范为JS整数;HTTP的Long版本仍为规范十进制字符串。
if (!native) f.args.demand.version = ''
const request = f.context.request
f.context.request = async (...args) => {
const response = await request(...args)
response.body.data = JSON.parse(JSON.stringify(response.body.data, (key, value) =>
/^(version|recordVersion|tripRecordVersion|offerRecordVersion)$/.test(key) ? native ? String(value) : '' : value))
return response
}
if (native) assert.equal((await bindLooseboardDemand(f.context, f.args)).status, 'CONFIRMED_ORIGINAL_ORDER')
else { await assert.rejects(bindLooseboardDemand(f.context, f.args), /散板原单/); assert.equal(f.writes(), 0) }
})
for (const [fault, maxWrites] of [['customer', 0], ['capacity', 0], ['network', 1], ['replay', 2], ['new order', 3], ['price', 3], ['binding', 4], ['disk', 0]]) {
test(`pool binding stops on ${fault} without another order or automatic retry`, async () => {
const f = fixture(fault)
await assert.rejects(bindLooseboardDemand(f.context, f.args))
assert.equal(f.args.demand.poolBinding.status, 'FAILED')
assert.equal(f.writes(), maxWrites)
assert.equal(f.calls.some(c => /cancel|\/iam\/|\/auth\/register/.test(c.path)), false)
})
}
test('foreign batch or unregistered trip is rejected before HTTP', async () => {
for (const alter of [f => { f.args.demand.marker = 'other' }, f => { f.context.createdResources.fleetTrips = [] }]) {
const f = fixture(); alter(f)
await assert.rejects(bindLooseboardDemand(f.context, f.args))
assert.equal(f.calls.length, 0)
}
})