import test from 'node:test' import assert from 'node:assert/strict' import { parsePoolArguments, poolPlan, runPoolAcceptance, assertPoolRemaining, assertSingleCommercial, shrinkingVehicleRequest, expiryWaitMs, poolLocalDateTime, poolPickScope, pickPoolDispatch, POOL_COVERAGE, POOL_REMAINING } from './fleet-capacity-pool-test-env.mjs' test('default and explicit plans make no network requests or invoke the mutating runner', async () => { const original = globalThis.fetch globalThis.fetch = async () => { throw Error('unexpected network') } try { for (const args of [[], ['--plan']]) { const config = parsePoolArguments(args) const plan = await runPoolAcceptance(config, { runner: async () => { throw Error('unexpected runner') } }) assert.equal(plan.execute, false) assert.equal(plan.environment, 'TEST') assert.equal(plan.runId, 'plan') assert.match(plan.boundary, /no network or filesystem writes/) } } finally { globalThis.fetch = original } }) test('execution needs explicit TEST, fresh run ID and current warehouse identifiers', () => { for (const args of [ ['--execute'], ['--execute', '--run-id', 'fresh', '--warehouse-id', '10', '--destination-warehouse-id', '11'], ['--execute', '--environment', 'gray', '--run-id', 'fresh', '--warehouse-id', '10', '--destination-warehouse-id', '11'], ['--execute', '--environment', 'TEST', '--run-id', '../reuse', '--warehouse-id', '10', '--destination-warehouse-id', '11'], ['--execute', '--plan'], ['--resume', 'old-report'], ]) assert.throws(() => parsePoolArguments(args)) const parsed = parsePoolArguments(['--execute', '--environment', 'TEST', '--run-id', 'pool-r1', '--warehouse-id', '10', '--destination-warehouse-id', '11']) assert.equal(parsed.execute, true) assert.equal(parsed.runId, 'pool-r1') }) test('plan distinguishes implemented HTTP scope from remaining whole-feature acceptance', () => { const plan = poolPlan(parsePoolArguments([])) assert.deepEqual(plan.coveredByThisEntry, POOL_COVERAGE) assert.deepEqual(plan.remainingSeparateAcceptance, POOL_REMAINING) assert.ok(plan.coveredByThisEntry.includes('both-business-types-real-pda-receipt')) assert.ok(plan.remainingSeparateAcceptance.includes('full-UI-1920x1080-and-network-request-budget')) assert.ok(plan.coveredByThisEntry.includes('weight-and-volume-independent-capacity-rejections')) assert.ok(plan.coveredByThisEntry.includes('paused-create-edit-confirm-rejected')) assert.ok(plan.coveredByThisEntry.includes('expired-cutoff-create-edit-confirm-rejected')) assert.ok(plan.coveredByThisEntry.includes('assigned-vehicle-disable-and-shrink-rejected')) assert.ok(plan.remainingSeparateAcceptance.includes('out-of-band-assigned-vehicle-drift-not-constructible-through-supported-api')) assert.match(plan.boundary, /unknown outcome/) assert.match(plan.boundary, /No automatic rerun or resume/) }) test('remaining capacity uses unique current destination and rejects unknown, other-stop or duplicate rows', () => { const offer = { capacityKnown: true, destinations: [{ destinationKey: 'FBA:A', remaining: { palletSpaces: 4 } }, { destinationKey: 'FBA:B', remaining: { palletSpaces: 30 } }] } assert.doesNotThrow(() => assertPoolRemaining(offer, 'FBA:A', 4)) for (const change of [o => { o.capacityKnown = false }, o => { o.destinations[0].remaining = null }, o => { o.destinations[0].destinationKey = 'FBA:C' }, o => { o.destinations.push(structuredClone(o.destinations[0])) }, o => { o.destinations[0].remaining.palletSpaces = 5 }]) { const altered = structuredClone(offer); change(altered) assert.throws(() => assertPoolRemaining(altered, 'FBA:A', 4), /EXACT_SEGMENT/) } }) test('successful confirmation replay must preserve commercial, booking, business type and customer identity', () => { const before = { bookingNo: 'FB-1', businessOrderNo: 'LB-1', businessType: 'LOCAL_LOOSEBOARD', customerId: '9' } assert.doesNotThrow(() => assertSingleCommercial(before, { ...before })) for (const field of Object.keys(before)) assert.throws(() => assertSingleCommercial(before, { ...before, [field]: 'OTHER' }), /IDENTITY_CHANGED/) assert.throws(() => assertSingleCommercial({ ...before, businessOrderNo: null }, { ...before }), /IDENTITY_CHANGED/) }) test('default executor rejects non-TEST process configuration before any fixture writes', async () => { const config = parsePoolArguments(['--execute', '--environment', 'TEST', '--run-id', 'pool-r1', '--warehouse-id', '10', '--destination-warehouse-id', '11']) await assert.rejects(runPoolAcceptance(config, { env: { CHONGCHONG_ENV: 'prod' } }), /Explicit TEST configuration/) }) test('vehicle shrink command preserves the authoritative full request and only changes capacity by one', () => { const vehicle = { id: '7', recordVersion: 11, plateNumber: 'TEST-7', model: 'Box Truck', fuelConsumptionPer100Km: 12.5, mileageKm: 100, driverOrDispatchCompany: 'TEST', phone: null, region: 'OVERSEAS', ownership: 'OWNED', remark: 'own fixture', maxPalletSpaces: 30, maxLoadKg: 18000, maxVolumeCbm: 90, status: 'IN_SERVICE' } const request = shrinkingVehicleRequest(vehicle) assert.equal(request.maxPalletSpaces, 29) for (const field of Object.keys(request).filter(name => name !== 'maxPalletSpaces')) assert.equal(request[field], vehicle[field]) assert.equal('status' in request, false) assert.equal('id' in request, false) assert.equal(vehicle.maxPalletSpaces, 30) }) test('vehicle matrix refuses incomplete snapshots instead of inventing capacity for a write', () => { for (const input of [null, {}, { id: '7', recordVersion: 1, maxPalletSpaces: 30 }, { id: '7', recordVersion: 1, maxPalletSpaces: 1, maxLoadKg: 18000, maxVolumeCbm: 90 }]) { assert.throws(() => shrinkingVehicleRequest(input), /SNAPSHOT_REQUIRED/) } }) test('cutoff wait is bounded and follows the returned instant without negative or unbounded sleeps', () => { const now = Date.parse('2030-01-01T08:00:00Z') assert.equal(expiryWaitMs('2030-01-01T08:00:08Z', now), 8300) assert.equal(expiryWaitMs('2030-01-01T07:59:00Z', now), 0) assert.throws(() => expiryWaitMs('invalid', now), /INVALID_SERVER_CUTOFF/) assert.throws(() => expiryWaitMs('2030-01-01T08:10:00Z', now), /BOUNDED_WINDOW/) }) test('LocalDateTime transport time keeps actual local wall clock while Instant dates remain zoned', () => { class ShanghaiDate extends Date { getTimezoneOffset() { return -480 } } class LosAngelesDate extends Date { getTimezoneOffset() { return 420 } } const instant = '2030-01-01T20:30:45.123Z' assert.equal(poolLocalDateTime(new ShanghaiDate(instant)), '2030-01-02T04:30:45') assert.equal(poolLocalDateTime(new LosAngelesDate(instant)), '2030-01-01T13:30:45') assert.equal(new ShanghaiDate(instant).toISOString(), instant) assert.equal(new LosAngelesDate(instant).toISOString(), instant) assert.throws(() => poolLocalDateTime(new Date('invalid')), /VALID_LOCAL_DATE_REQUIRED/) }) test('PDA namespace belongs to the exact run, customer and dispatch while parent evidence stays shared', () => { const context = { marker: 'ORIGINAL-RUN', steps: [], createdResources: {} }, first = { customerId: '9', dispatchNo: 'DS-A' } const a = poolPickScope(context, first), replay = poolPickScope(context, first) assert.equal(a.marker, replay.marker) assert.notEqual(a.marker, poolPickScope(context, { ...first, dispatchNo: 'DS-B' }).marker) assert.notEqual(a.marker, poolPickScope(context, { ...first, customerId: '10' }).marker) assert.notEqual(a.marker, poolPickScope({ ...context, marker: 'OTHER-RUN' }, first).marker) assert.equal(a.steps, context.steps) assert.equal(a.createdResources, context.createdResources) assert.equal(context.marker, 'ORIGINAL-RUN') assert.throws(() => poolPickScope(context, { dispatchNo: 'DS-A' }), /PICK_SCOPE_REQUIRED/) }) test('real pickAll helper handles two same-customer dispatches with separate pick/complete keys and exact replays', async () => { const operations = new Map(), requests = [], steps = [], picked = new Map() const dispatches = ['DS-A', 'DS-B'] const context = { marker: 'SAME-CUSTOMER-RUN', steps, createdResources: {}, addStep(_module, _name, _response, passed) { steps.push(passed) }, assert(_module, _name, _response, passed) { assert.equal(Boolean(passed), true) }, addCoverageGap() { assert.fail('unexpected coverage gap') }, async request(method, path, body) { const dispatchNo = path.split('/dispatches/')[1].split('/')[0], index = dispatches.indexOf(dispatchNo) assert.ok(index >= 0) const response = data => ({ http: 200, body: { code: '200', data }, requestId: 'test', traceId: 'test' }) if (method === 'GET') return response({ items: [{ dispatchItemId: `${index + 1}`, scheduledPackages: 1, pickedPackages: picked.get(dispatchNo) || 0, positions: [{ id: `${index + 100}`, availablePackages: 1 }] }] }) requests.push({ method, path, body: structuredClone(body) }) const prior = operations.get(body.idempotencyKey), payload = JSON.stringify([path, body]) if (prior) { if (prior.payload !== payload) return { http: 200, body: { code: 'A0409', message: 'Idempotency key was reused with a different request' } } return response({ ...prior.result, replayed: true }) } let result if (path.endsWith('/pick')) { picked.set(dispatchNo, 1); result = { pickedPackages: 1 } } else result = { status: 'READY_TO_DEPART', plannedPackages: 1, pickedPackages: 1, remainingPackages: 0, replayed: false } operations.set(body.idempotencyKey, { payload, result }) return response(result) }, } for (const dispatchNo of dispatches) await pickPoolDispatch(context, 'test-pda', { customerId: '9', dispatchNo }) assert.equal(operations.size, 4) assert.equal(requests.length, 8) assert.ok(steps.every(Boolean)) for (let index = 0; index < requests.length; index += 2) assert.deepEqual(requests[index], requests[index + 1]) }) test('failed helper result stops the pool stage immediately instead of appending a misleading generic failure', async () => { const context = { marker: 'R', steps: [] } await assert.rejects(pickPoolDispatch(context, 'test', { customerId: '9', dispatchNo: 'DS-A' }, async () => false), /PDA_PICK_FAILED:DS-A/) })