Files

103 lines
6.4 KiB
JavaScript
Raw Permalink Normal View History

import test from 'node:test'
import assert from 'node:assert/strict'
import { CARRIER_EXCEPTION_CODES, carrierExceptionShapeErrors, carrierExceptionTransitionErrors,
captureCarrierExceptionEvidence } from './phase3-carrier-schedule-queries.mjs'
const fixture = () => ({ marker: 'current', queryId: '2105227585104384001', detail: {
query: { query: { id: '2105227585104384001', customerId: '0', oceanBookingId: '2105227599885111297',
containerBookingId: '2105227585104384002', latestStandardNode: 'IN_TRANSIT', latestActualAt: '2026-10-02T09:00:00' } },
nodes: [{ id: 'actual', standardNode: 'IN_TRANSIT', actualAt: '2026-10-02T09:00:00' },
{ id: 'estimated', standardNode: 'ARRIVED_DESTINATION_PORT', estimatedAt: '2026-10-20T09:00:00' }],
exceptions: [], histories: [],
} })
const fact = (code, active = true, sequence = 1) => ({ id: `210522758510438401${sequence}`,
providerCode: 'TEST_PROVIDER', providerEventId: `${code}-${active}`, providerStatus: active ? 'HOLD' : 'RELEASE',
exceptionCode: code, active, observedAt: '2026-10-02T10:00:00', locationCode: 'USLAX', locationName: 'Los Angeles',
sourceReference: 'controlled-provider', rawPayloadHash: (active ? 'a' : 'b').repeat(64), createdAt: '2026-10-02T10:00:01' })
function append(before, value) {
const after = structuredClone(before)
after.detail.exceptions.push(value)
after.detail.histories.push({ id: value.id, action: 'EXCEPTION_OBSERVED', reason: value.exceptionCode })
return after
}
for (const code of CARRIER_EXCEPTION_CODES) {
test(`${code}: append and release retain original exception and both normal time facts`, () => {
const before = fixture(), active = fact(code), released = fact(code, false, 2)
const after = append(before, active)
assert.deepEqual(carrierExceptionTransitionErrors(before, after, { kind: 'APPEND', expected: active }), [])
assert.deepEqual(carrierExceptionTransitionErrors(after, append(after, released), { kind: 'RELEASE', expected: released }), [])
assert.deepEqual(carrierExceptionTransitionErrors(after, structuredClone(after), { kind: 'REPLAY', expected: active }), [])
assert.deepEqual(carrierExceptionTransitionErrors(after, structuredClone(after), { kind: 'CONFLICT', expected: { ...active, rawPayloadHash: 'c'.repeat(64) } }), [])
})
}
test('replay/conflict fail on changed fact, extra history, missing original event or wrong payload hash', () => {
const original = fact('CUSTOMS_HOLD'), before = append(fixture(), original)
for (const mutate of [
value => { value.detail.exceptions[0].active = false },
value => { value.detail.histories.push({ id: 'extra', action: 'EXCEPTION_OBSERVED' }) },
value => { value.detail.nodes[1].estimatedAt = '2026-10-21T09:00:00' },
value => { value.detail.query.query.latestStandardNode = 'PICKUP_READY' },
value => { value.marker = 'other' },
]) {
const after = structuredClone(before); mutate(after)
assert.ok(carrierExceptionTransitionErrors(before, after, { kind: 'REPLAY', expected: original }).length)
}
assert.ok(carrierExceptionTransitionErrors(fixture(), fixture(), { kind: 'REPLAY', expected: original }).length)
assert.ok(carrierExceptionTransitionErrors(before, before, { kind: 'CONFLICT', expected: original }).length)
})
test('release replacing the active row, deleting original history or absent estimated baseline is rejected', () => {
const active = fact('TERMINAL_HOLD'), release = fact('TERMINAL_HOLD', false, 2)
const before = append(fixture(), active)
for (const mutate of [
value => { value.detail.exceptions.shift() },
value => { value.detail.histories.shift() },
value => { value.detail.nodes.pop() },
]) {
const after = append(before, release); mutate(after)
assert.ok(carrierExceptionTransitionErrors(before, after, { kind: 'RELEASE', expected: release }).length)
}
const empty = fixture(); empty.detail.nodes.pop()
assert.ok(carrierExceptionTransitionErrors(empty, append(empty, active), { kind: 'APPEND', expected: active }).length)
})
test('reject customs declaration codes, duplicate supplier event, malformed hash and absent source fields', () => {
for (const mutate of [
value => { value.detail.exceptions[0].exceptionCode = 'INSPECTION' },
value => { value.detail.exceptions.push({ ...value.detail.exceptions[0], id: '2105227585104384019' }) },
value => { value.detail.exceptions[0].rawPayloadHash = 'bad' },
value => { value.detail.exceptions[0].providerCode = '' },
value => { value.detail.nodes[0].standardNode = 'CUSTOMS_HOLD' },
]) {
const value = append(fixture(), fact('UNKNOWN_HOLD')); mutate(value)
assert.ok(carrierExceptionShapeErrors(value.detail).length)
}
})
test('provider DTO permits absent location and source reference; supplied values still match exactly', () => {
const active = { ...fact('UNKNOWN_HOLD'), locationCode: null, locationName: null, sourceReference: null }
const before = fixture(), after = append(before, structuredClone(active))
assert.deepEqual(carrierExceptionShapeErrors(after.detail), [])
assert.deepEqual(carrierExceptionTransitionErrors(before, after, { kind: 'APPEND', expected: active }), [])
after.detail.exceptions[0].sourceReference = 'changed'
assert.ok(carrierExceptionTransitionErrors(before, after, { kind: 'APPEND', expected: active }).length)
})
test('real API checkpoint uses only original detail GET and rejects another marker before any call', async () => {
const before = fixture(), calls = [], original = globalThis.fetch
const context = { marker: 'current', options: { gateway: 'https://offline.invalid' }, token: 'offline',
apiSuccess: (_module, _name, response) => response.body.data, assert: (_module, _name, _response, passed) => assert.ok(passed) }
const resource = { queryId: before.queryId, marker: 'current', ownedByModule: true, triggerSource: 'OUTBOUND_CONFIRM' }
globalThis.fetch = async (url, options) => { calls.push({ url, method: options.method }); return new Response(JSON.stringify({ code: '200', data: before.detail })) }
try {
const captured = await captureCarrierExceptionEvidence(context, resource)
assert.deepEqual(captured.detail, before.detail)
assert.deepEqual(calls.map(item => item.method), ['GET'])
assert.ok(calls[0].url.endsWith(`/api/platform/v1/carrier-schedule-queries/${before.queryId}`))
await assert.rejects(captureCarrierExceptionEvidence(context, { ...resource, marker: 'other' }), /current-marker/)
assert.equal(calls.length, 1)
} finally { globalThis.fetch = original }
})