import test from 'node:test' import assert from 'node:assert/strict' import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { run } from './phase4-overseas-business.mjs' const here = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(here, 'phase4-overseas-business.mjs'), 'utf8') function response(data, code = '200') { return { http: 200, body: { code, message: code === '200' ? 'success' : 'conflict', data }, requestId: 'request-test', traceId: 'trace-test' } } function page(records = []) { return { records, page: 1, size: 20, total: records.length, pages: records.length ? 1 : 0 } } function fixture({ ownedPurchase = false, historicalPurchase = false } = {}) { const calls = []; const steps = []; const gaps = [] const state = { truck: null, looseboard: null, purchase: { id: '30001', orderNo: 'OP1', customerId: '10001', purchaseWarehouseId: '20001', purchaseCategory: '家居', productName: '置物架', purchaseQuantity: 2, inboundQuantity: 0, inventoryQuantity: 0, status: 'PENDING_REVIEW', version: 0 }, } const marker = 'HTTP-20260821-001' const context = { marker, calls, steps, gaps, context: {}, createdResources: ownedPurchase ? { overseasProcurement: { marker, orderNo: 'OP1', customerId: '10001' } } : {}, async request(method, requestPath, body) { calls.push({ channel: 'domestic', method, path: requestPath, body }); return response(page([{ id: '10001', tenantName: '客户甲', status: 'ACTIVE' }])) }, async requestOverseas(method, requestPath, body) { calls.push({ channel: 'overseas', method, path: requestPath, body }) if (requestPath.includes('/customer-options')) return response([{ customerId: '10001', customerName: '客户甲' }]) if (requestPath.includes('/warehouse-options')) return response([{ warehouseId: '20001', warehouseCode: 'LAX', warehouseName: '洛杉矶仓', countryCode: 'US' }]) if (requestPath.includes('/overseas-procurements?') && method === 'GET') return response(page(ownedPurchase || historicalPurchase ? [state.purchase] : [])) if (requestPath.includes('/overseas-procurements/OP1?') && method === 'GET') return response({ summary: state.purchase, remark: marker }) if (requestPath.includes('/overseas-procurements/OP1?') && method === 'PATCH') { state.purchase = { ...state.purchase, ...body, version: state.purchase.version + 1 }; return response({ summary: state.purchase }) } if (requestPath.includes('/us-truck-orders?') && method === 'POST') { state.truck = { id: '40001', orderNo: 'TK1', customerId: '10001', status: 'PENDING_REVIEW', version: 0, ...body }; return response({ summary: state.truck }) } if (requestPath.includes('/us-truck-orders/TK1/status?') && method === 'PATCH') { if (Number(body.version) !== state.truck.version) return response(null, 'A0409'); state.truck = { ...state.truck, status: body.status, version: state.truck.version + 1 }; return response({ summary: state.truck }) } if (requestPath.includes('/us-truck-orders/TK1?') && method === 'GET') return response({ summary: state.truck }) if (requestPath.includes('/us-truck-orders/TK1?') && method === 'PATCH') { if (Number(body.version) !== state.truck.version) return response(null, 'A0409'); state.truck = { ...state.truck, ...body, version: state.truck.version + 1 }; return response({ summary: state.truck }) } if (requestPath.includes('/local-looseboard-orders?') && method === 'POST') { state.looseboard = { id: '50001', orderNo: 'LB1', customerId: '10001', status: 'PENDING_ACCEPTANCE', version: 0, ...body }; return response({ summary: state.looseboard }) } if (requestPath.includes('/local-looseboard-orders/LB1/status?') && method === 'PATCH') { if (Number(body.version) !== state.looseboard.version) return response(null, 'A0409'); state.looseboard = { ...state.looseboard, status: body.status, version: state.looseboard.version + 1 }; return response({ summary: state.looseboard }) } if (requestPath.includes('/local-looseboard-orders/LB1?') && method === 'GET') return response({ summary: state.looseboard }) if (requestPath.includes('/local-looseboard-orders/LB1?') && method === 'PUT') { if (Number(body.version) !== state.looseboard.version) return response(null, 'A0409'); state.looseboard = { ...state.looseboard, ...body, version: state.looseboard.version + 1 }; return response({ summary: state.looseboard }) } throw new Error(`unexpected ${method} ${requestPath}`) }, apiSuccess(module, name, result, evidence, options) { const passed = result.http === 200 && String(result.body?.code) === '200'; steps.push({ module, name, passed, evidence, options }); return passed ? result.body.data : null }, assert(module, name, result, passed, evidence, options) { steps.push({ module, name, passed: Boolean(passed), result, evidence, options }) }, addStep(module, name, result, passed, evidence, options) { steps.push({ module, name, passed: Boolean(passed), result, evidence, options }) }, addCoverageGap(...args) { gaps.push(args) }, } return context } test('module is context injected and excludes forbidden business surfaces', () => { assert.match(source, /export async function run\(context\)/) assert.doesNotMatch(source, /https?:\/\/|process\.env|fetch\(/) for (const forbidden of ['/merchant/', '/review', '/outbounds', '/receive-pallets', '/outbound', '/delivery', '/dispatch', '/export']) assert.equal(source.includes(forbidden), false, forbidden) assert.doesNotMatch(source, /requestOverseas\('DELETE'/) }) test('marker truck and looseboard cover create detail edit stale conflict and finally cancel', async () => { const context = fixture() await run(context) assert.equal(context.steps.every((step) => step.passed), true, context.steps.filter((step) => !step.passed).map((step) => `${step.name}: ${step.evidence}`).join('\n')) assert.deepEqual(context.calls.filter((call) => call.method === 'POST').map((call) => call.path), [ '/api/platform/v1/last-leg/us-truck-orders?customerId=10001', '/api/platform/v1/last-leg/local-looseboard-orders?customerId=10001', ]) assert.equal(context.calls.filter((call) => call.method === 'PATCH' && call.path.includes('/us-truck-orders/')).length, 3) assert.equal(context.calls.filter((call) => call.method === 'PUT' && call.path.includes('/local-looseboard-orders/')).length, 2) assert.equal(context.calls.filter((call) => call.method === 'PATCH' && call.path.includes('/local-looseboard-orders/')).length, 1) const statusCalls = context.calls.filter((call) => call.path.includes('/status?')) assert.deepEqual(statusCalls.map((call) => [call.method, call.path, call.body.status]), [ ['PATCH', '/api/platform/v1/last-leg/us-truck-orders/TK1/status?customerId=10001', 'CANCELLED'], ['PATCH', '/api/platform/v1/last-leg/local-looseboard-orders/LB1/status?customerId=10001', 'CANCELLED'], ]) assert.ok(statusCalls.every((call) => Number(call.body.version) === 1)) assert.equal(context.createdResources.phase4OverseasBusiness.truck.marker, context.marker) assert.equal(context.createdResources.phase4OverseasBusiness.looseboard.marker, context.marker) assert.equal(context.createdResources.phase4OverseasBusiness.truck.finalStatus, 'CANCELLED') assert.equal(context.createdResources.phase4OverseasBusiness.looseboard.finalStatus, 'CANCELLED') assert.equal(context.createdResources.phase4OverseasBusiness.truck.retained, false) assert.equal(context.createdResources.phase4OverseasBusiness.looseboard.retained, false) assert.equal(context.gaps.filter((gap) => gap[4]?.includes('retained-marker-test-data')).length, 0) assert.ok(context.gaps.every((gap) => !/requestId=missing|traceId=missing/.test(gap[3]))) }) test('historical procurement data is never patched without marker ownership', async () => { const context = fixture({ historicalPurchase: true }) await run(context) assert.equal(context.calls.some((call) => call.method === 'PATCH' && call.path.includes('/overseas-procurements/')), false) assert.equal(context.gaps.some((gap) => gap[4] === 'missing-marker-owned-procurement'), true) }) test('marker-owned procurement may be patched but never created, reviewed or shipped', async () => { const context = fixture({ ownedPurchase: true }) await run(context) const purchaseWrites = context.calls.filter((call) => call.path.includes('/overseas-procurements') && call.method !== 'GET') assert.deepEqual(purchaseWrites.map((call) => call.method), ['PATCH']) assert.match(purchaseWrites[0].body.productSpecification, new RegExp(context.marker)) assert.equal(context.createdResources.phase4OverseasBusiness.purchase.marker, context.marker) }) test('contract locks real candidates, idempotency, version conflicts and trace evidence', () => { for (const token of ['/api/platform/v1/iam/tenants?page=1&size=200&status=ACTIVE', '/overseas-procurements/customer-options?limit=200', '/overseas-procurements/warehouse-options', 'idempotencyKey', 'phase4-truck', 'phase4-looseboard', '旧 version', '/status', "status: 'CANCELLED'", 'finally', 'requestId=', 'traceId=', 'createdResources.phase4OverseasBusiness']) assert.ok(source.includes(token), token) })