import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { CONTAINER_CUSTOMS_FIXTURE_KINDS, CONTAINER_CUSTOMS_MATRIX, EXACT_50_MB, READ_ONLY_DB_EVIDENCE, REQUIRED_ROUTE_OPERATIONS, validateContainerCustomsFixtures, validateRouteContract, xlsxMagic, zeroDrift, } from './container-customs-acceptance-matrix.mjs' const source = readFileSync(new URL('./phase3-container-customs.mjs', import.meta.url), 'utf8') const fixtureSource = readFileSync(new URL('./phase3-container-customs-fixture.mjs', import.meta.url), 'utf8') const entrySource = readFileSync(new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8') test('matrix covers three isolated LOADED container kinds', () => { assert.deepEqual(CONTAINER_CUSTOMS_FIXTURE_KINDS, ['ALL_BUY_DECLARATION', 'ALL_TAX_REFUND', 'MIXED']) const fixtures = { marker: 'M', containers: CONTAINER_CUSTOMS_FIXTURE_KINDS.map((kind, index) => ({ marker: 'M', kind, status: 'LOADED', loadingPlanId: String(100 + index), containerBookingId: String(200 + index), inbounds: [{ inboundId: String(300 + index), customerId: String(400 + index), taxMode: kind === 'ALL_BUY_DECLARATION' ? 'BUY_DECLARATION' : 'TAX_REFUND' }], })) } assert.equal(validateContainerCustomsFixtures(fixtures, 'M'), true) assert.equal(validateContainerCustomsFixtures({ marker: 'M', containers: [fixtures.containers[2]] }, 'M', ['MIXED']), true) assert.equal(validateContainerCustomsFixtures({ ...fixtures, marker: 'OLD' }, 'M'), false) }) test('mixed fixture producer is registered and uses only public HTTP composition', () => { assert.match(entrySource, /CONFIGURED_MODULES[^\n]*'phase3-container-customs'/) assert.match(entrySource, /\['phase3-container-customs', \['merchant-qualification-fixture'\]\]/) assert.match(entrySource, /phase3-container-customs-fixture\.mjs/) assert.match(fixtureSource, /primary: 'BUY_DECLARATION', incremental: 'TAX_REFUND'/) assert.match(fixtureSource, /phase3-loading\.mjs/) assert.match(fixtureSource, /phase3-loading-finalize\.mjs/) assert.match(fixtureSource, /LOADING_LIST_BUY_DECLARATION_ITEMS/) assert.match(fixtureSource, /merchantQualificationFixture/) assert.match(fixtureSource, /merchantPlatformDetail/) assert.doesNotMatch(fixtureSource, /customerToken:/) assert.doesNotMatch(fixtureSource, /\b(?:INSERT\s+INTO|DELETE\s+FROM|UPDATE\s+(?:fl_|ll_|wh_|ord_))/i) }) test('coverage matrix freezes every requested product boundary', () => { const text = CONTAINER_CUSTOMS_MATRIX.map((item) => `${item.scenario}:${item.expected}`).join('\n') for (const token of ['买单XLSX', '多对多', '覆盖', '改关联', '删除', '冻结', '回执确认', '报关行执行', '完税文件', '最后上传', '混合', '缺资料', '开始后锁定', '客户隔离', '买单隐藏', '50MiB', '任意格式', '幂等', '并发', 'A0409', '零漂移', '自动离仓', 'Outbox', '历史', 'Admin与Client权限']) { assert.match(text, new RegExp(token)) } }) test('route adapter fails closed until final backend and frontend contracts align', () => { assert.equal(validateRouteContract({}), false) const routes = { version: 'final', ...Object.fromEntries(REQUIRED_ROUTE_OPERATIONS.map((name) => [name, () => null])) } assert.equal(validateRouteContract(routes), true) assert.match(source, /后端Controller\/OpenAPI与Admin\/Client最终路径尚未对齐,禁止猜测URL发请求/) assert.doesNotMatch(source, /https?:\/\//) }) test('HTTP scenario contains file, state, idempotency, concurrency and zero-drift probes', () => { assert.doesNotMatch(source, /\bcodeOf\(/) for (const token of ['EXACT_50_MB + 1', '.customblob', 'application/octet-stream', '缺退税资料禁止开始且零漂移', '开始后资料范围锁定A0409零漂移', "['上传'", "['覆盖'", "['改关联'", "['删除'", '开始后${label}锁定A0409零漂移', '首次发送报关行并生成独立批次', '混合柜冻结资料首次发送报关行并生成独立批次', '回执未确认且未发送执行时禁止上传完税文件', '客户确认整份回执后仍处于报关中', '真实报关完税文件齐全后纯退税柜完成', '客户确认回执后仍未完成整柜', '混合柜平台详情精确包含BUY与TAX长ID票', 'Client只见本客户TAX票且完全隐藏BUY票', '买单导出只处理实际装柜BUY行', '混合柜最后一份完成文件后整柜COMPLETED', '自动离仓只写一次SYSTEM历史', '自动离仓只创建一个OUTBOUND_CONFIRM长ID任务', 'documentId: customer.documentId, expectedVersion: 0', '完成文件未成功或同键重放未收敛,已停止后续自动离仓写入', '已停止后续完成写入并保留现场', '自动离仓失败不回滚报关完成', '自动或待条件重试后整柜单次离仓', '同幂等键异载荷A0409', 'Promise.all', 'requestId=', 'traceId=', 'xlsxMagic']) { assert.match(source, new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) } assert.equal(EXACT_50_MB, 52_428_800) assert.equal(zeroDrift({ a: 1 }, { a: 1 }), true) assert.equal(xlsxMagic(Uint8Array.from([0x50, 0x4b, 0x03, 0x04])), true) }) test('database evidence list covers atomicity, history, dispatch and outbox without embedding SQL writes', () => { for (const table of ['fl_customs_container', 'fl_customs_customer_document_inbound', 'fl_customs_completion_document', 'fl_customs_final_document', 'fl_customs_command', 'fl_customs_container_history', 'fl_outbound_dispatch', 'fl_event_outbox']) assert.ok(READ_ONLY_DB_EVIDENCE.includes(table), table) assert.doesNotMatch(source, /\b(?:INSERT|UPDATE|DELETE)\s+(?:INTO|FROM|[a-z_])/i) })