import assert from 'node:assert/strict' import { existsSync, readFileSync } from 'node:fs' import { dirname, resolve } from 'node:path' import test from 'node:test' import { fileURLToPath } from 'node:url' import { normalizeModuleOrder } from './admin-test-env-acceptance.mjs' const scriptsDir = dirname(fileURLToPath(import.meta.url)) const backendScript = readFileSync(resolve(scriptsDir, 'backend-full-regression.ps1'), 'utf8') const adminAcceptance = readFileSync(resolve(scriptsDir, 'admin-test-env-acceptance.mjs'), 'utf8') test('backend full regression includes file reactor and critical file/container coverage', () => { assert.match(backendScript, /-pl["',\s\S]*order,firstleg,iam,gateway,file/) for (const required of [ 'file/src/test/java/com/baiyue/file/controller/QualificationFileContractTest.java', 'file/src/test/java/com/baiyue/file/controller/InternalBusinessFileControllerTest.java', 'file/src/test/java/com/baiyue/file/service/InternalBusinessFileServiceTest.java', 'firstleg/src/test/java/com/baiyue/firstleg/controller/ContainerControllerContractTest.java', 'firstleg/src/test/java/com/baiyue/firstleg/controller/LoadingListControllerContractTest.java', 'firstleg/src/test/java/com/baiyue/firstleg/repository/ContainerOverviewSqlContractTest.java', 'firstleg/src/test/java/com/baiyue/firstleg/service/ContainerOverviewServiceTest.java', 'firstleg/src/test/java/com/baiyue/firstleg/service/LoadingListServiceTest.java', ]) assert.match(backendScript, new RegExp(required.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) }) test('test-environment full acceptance registers container overview module', () => { const modulePath = resolve(scriptsDir, 'admin-test-env-modules', 'phase3-container-overview.mjs') if (!adminAcceptance.includes('phase3-container-overview') || !existsSync(modulePath)) { assert.fail('default acceptance module phase3-container-overview is not registered yet') } }) test('test-environment full acceptance executes warehouse-scoped booking channel isolation', () => { const loadingModulePath = resolve(scriptsDir, 'admin-test-env-modules', 'phase3-container-loading.mjs') const fixturePath = resolve(scriptsDir, 'admin-test-env-modules', 'ocean-booking-fixture.mjs') assert.match(adminAcceptance, /CONFIGURED_MODULES\s*=\s*\[[^\]]*'phase3-container-loading'/s) assert.ok(existsSync(loadingModulePath), 'phase3-container-loading module is missing') assert.ok(existsSync(fixturePath), 'shared ocean booking fixture is missing') const loadingModule = readFileSync(loadingModulePath, 'utf8') const fixture = readFileSync(fixturePath, 'utf8') assert.match(loadingModule, /publishPlatformLogisticsChannels\(context, warehouseId, MODULE\)/) assert.match(loadingModule, /selectPlatformChannelIsolationPair/) assert.match(loadingModule, /BLOCKED_FIXTURE/) assert.match(fixture, /\/api\/platform\/v1\/ocean-bookings\/channels/) assert.match(fixture, /createdResources\.platformLogisticsChannels/) }) test('test-environment full acceptance keeps assigned and unassigned customer booking chains', () => { const loadingIndex = adminAcceptance.indexOf("'phase3-container-loading'") const bookingIndex = adminAcceptance.indexOf("'ocean-bookings'") assert.ok(loadingIndex >= 0 && bookingIndex > loadingIndex, 'ocean-bookings must run after the assigned-customer container fixture') const bookingModule = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'ocean-bookings.mjs'), 'utf8') assert.match(bookingModule, /oceanBookingDraftWithoutCustomer/) assert.match(bookingModule, /createdResources\.oceanBookingUnassignedCustomer/) assert.match(bookingModule, /customerId == null[\s\S]*customerName == null/) assert.match(bookingModule, /status === 'CONFIRMED'[\s\S]*containers\?\.length === 1/) assert.match(bookingModule, /keyword=\$\{encodeURIComponent\(bookingNo\)\}/) assert.doesNotMatch(bookingModule, /keyword=\$\{encodeURIComponent\(context\.marker\)\}/) assert.match(bookingModule, /指定客户订舱持久化本轮客户范围快照/) assert.match(bookingModule, /phase3Loading[\s\S]*phase3ContainerLoading/) }) test('test-environment loading chains push without a number and open PDA only after all prerequisites', () => { const containerLoading = readFileSync( resolve(scriptsDir, 'admin-test-env-modules', 'phase3-container-loading.mjs'), 'utf8') const bridgeLoading = readFileSync( resolve(scriptsDir, 'admin-test-env-modules', 'phase3-loading.mjs'), 'utf8') assert.match(containerLoading, /realContainerBookingId: id\(requirement\.containerBookingId\)/) const pushIndex = bridgeLoading.indexOf('无真实柜号推送预装成功并冻结柜次明细') const absentIndex = bridgeLoading.indexOf('无号 push 成功后 PDA 查询明确 A0404') const linkIndex = bridgeLoading.indexOf('模拟柜原地合并三期 CONFIRMED 真实订舱柜') const releaseIndex = bridgeLoading.indexOf('三期订舱携带已冻结运输快照并放舱') const confirmIndex = bridgeLoading.indexOf('计划级原子确认整份预装并触发唯一 PDA 任务') const pdaIndex = bridgeLoading.indexOf('读取柜次级 PDA 唯一事实任务') assert.ok(pushIndex >= 0 && absentIndex > pushIndex && linkIndex > absentIndex && releaseIndex > linkIndex && confirmIndex > releaseIndex && pdaIndex > confirmIndex) assert.match(bridgeLoading, /codeOf\(missingContainerTaskResponse\) === 'A0404'/) assert.match(bridgeLoading, /push exact replay 对计划版本历史关联和任务零漂移/) assert.match(bridgeLoading, /bookingReleased\?\.oceanBooking\?\.status === 'RELEASED'/) assert.match(bridgeLoading, /loading-plans\/\$\{loadingPlanId\}\/confirm/) assert.match(bridgeLoading, /readiness\?\.readyForPda === true/) assert.match(bridgeLoading, /计划级确认同 key 异参返回冲突[\s\S]*已确认计划使用新 key 重复确认返回冲突/) assert.doesNotMatch(bridgeLoading, /\/preload\/confirming|\/preload\/confirm\?tenantId=/) const containerPushIndex = containerLoading.indexOf('无真实柜号推送预装计划成功') const containerLinkIndex = containerLoading.indexOf('首次关联真实已确认订舱柜') const containerReleaseIndex = containerLoading.indexOf('订舱携带已冻结运输快照放舱并满足 PDA 门禁') const containerConfirmIndex = containerLoading.indexOf('计划级原子确认整份预装并触发唯一 PDA 任务') const containerPdaIndex = containerLoading.indexOf('查询本轮柜次 PDA 拣货任务') assert.ok(containerPushIndex >= 0 && containerLinkIndex > containerPushIndex && containerReleaseIndex > containerLinkIndex && containerConfirmIndex > containerReleaseIndex && containerPdaIndex > containerConfirmIndex) assert.match(containerLoading, /loading-plans\/\$\{planId\}\/confirm/) assert.match(containerLoading, /readiness\?\.readyForPda === true/) assert.match(containerLoading, /计划级确认同 key 异参返回冲突[\s\S]*已确认计划使用新 key 重复确认返回冲突/) assert.doesNotMatch(containerLoading, /\/preload\/confirming|\/preload\/confirm\?tenantId=/) }) test('default Admin HTTP entry carries evidence chain through settlement-aware PDA completion', () => { const focused = normalizeModuleOrder([ 'merchant-qualification-fixture', 'orders', 'inbound-measurement', 'phase3-container-loading', 'phase3-loading', 'phase3-container-overview', 'phase3-pda-convergence', 'phase3-evidence-gate', 'phase3-customs', 'phase3-loading-finalize', ]) assert.deepEqual(focused, [ 'merchant-qualification-fixture', 'orders', 'inbound-measurement', 'phase3-container-loading', 'phase3-loading', 'phase3-container-overview', 'phase3-pda-convergence', 'phase3-evidence-gate', 'phase3-customs', 'phase3-loading-finalize', ]) const loading = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-loading.mjs'), 'utf8') const evidenceGate = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-evidence-gate.mjs'), 'utf8') const convergence = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-pda-convergence.mjs'), 'utf8') const customs = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-customs.mjs'), 'utf8') const finalize = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-loading-finalize.mjs'), 'utf8') assert.match(loading, /context\.createdResources\.phase3Loading = \{[\s\S]*marker: context\.marker/) for (const field of ['inboundId', 'loadingPlanId', 'containerBookingId', 'canonicalPdaTaskId']) { assert.match(loading, new RegExp(`context\\.createdResources\\.phase3Loading = \\{[\\s\\S]*${field}`)) } assert.match(loading, /const evidenceTypes = \['PHOTO_STEP_1', 'PHOTO_STEP_2', 'PHOTO_STEP_3', 'PHOTO_STEP_4', 'SEAL'\]/) assert.match(evidenceGate, /fixture\??\.marker !== context\.marker/) assert.match(evidenceGate, /taskId[\s\S]*inboundId[\s\S]*loadingPlanId[\s\S]*containerBookingId/) assert.match(convergence, /pending 与 detail 使用同一 workflowStatus 和未完成数量事实/) assert.match(convergence, /AWAITING_REVIEW 已全拣任务 actions 为空且不再提交 batch/) assert.match(convergence, /AWAITING_REVIEW 可进入装柜取证只读入口/) assert.match(customs, /createdResources\?\.phase3Loading[\s\S]*container\?\.finalStatus/) assert.match(finalize, /fixture\?\.marker !== context\.marker/) assert.doesNotMatch(finalize, /BLOCKED_CONTRACT/) assert.ok(finalize.indexOf('const taskPath =') < finalize.indexOf('结算递增 inboundVersion 后 final complete 必须使用最新版本')) assert.match(finalize, /结算或版本冲突失败后 task\/plan\/inbound\/operation 全部零写入/) assert.match(finalize, /结算递增版本后实际完成分片唯一且柜次身份稳定/) assert.doesNotMatch(finalize, /truck\?\.finalStatus === 'COMPLETED'/) }) test('Finance-only HTTP entry expands producer prerequisites and runs downloads last', () => { const focused = normalizeModuleOrder(['finance-downloads', 'finance-settlement-full']) assert.deepEqual(focused.slice(0, 4), [ 'merchant-qualification-fixture', 'orders', 'inbound-measurement', 'phase3-container-loading', ]) assert.deepEqual(focused.slice(-4), ['finance-full-fixtures', 'finance-reconciliation-full', 'finance-settlement-full', 'finance-downloads']) })