174 lines
11 KiB
JavaScript
174 lines
11 KiB
JavaScript
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('backend full regression rejects Mapper registration drift before Maven', () => {
|
|
assert.match(backendScript, /scripts\/mapper-scan-contract\.mjs/)
|
|
assert.match(backendScript, /& node \$mapperScanContract[\s\S]*& \$MavenCommand @mavenArgs/)
|
|
})
|
|
|
|
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 the DRAFT to RELEASED booking chain', () => {
|
|
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, /创建订舱 DRAFT(不生成真实柜号\/货柜分配)/)
|
|
assert.match(bookingModule, /containerRequirements/)
|
|
assert.match(bookingModule, /完整 DRAFT 放舱为 RELEASED 且冻结五项运输事实/)
|
|
assert.match(bookingModule, /RELEASED 编辑拒绝且零写入/)
|
|
assert.doesNotMatch(bookingModule, /realContainerBookingId|CHANGE_PENDING|CANCELLED/)
|
|
})
|
|
|
|
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, /oceanBookingId: bookingId, requirementId: id\(requirement\.id\), containerNo: realContainerNo/)
|
|
assert.doesNotMatch(containerLoading, /realContainerBookingId/)
|
|
|
|
const pushIndex = bridgeLoading.indexOf('分配后自动建立预装关联且柜次计划可读')
|
|
const absentIndex = bridgeLoading.indexOf('无号 push 成功后 PDA 查询明确 A0404')
|
|
const releaseIndex = bridgeLoading.indexOf('三期订舱 RELEASED 冻结运输快照')
|
|
const linkIndex = bridgeLoading.indexOf('模拟柜原地关联三期 RELEASED 订舱需求并补真实柜号')
|
|
const confirmIndex = bridgeLoading.indexOf('计划级原子确认整份预装并触发唯一 PDA 任务')
|
|
const pdaIndex = bridgeLoading.indexOf('读取柜次级 PDA 唯一事实任务')
|
|
assert.ok(pushIndex >= 0 && absentIndex > pushIndex
|
|
&& releaseIndex > absentIndex && linkIndex > releaseIndex && confirmIndex > linkIndex && pdaIndex > confirmIndex)
|
|
assert.match(bridgeLoading, /codeOf\(missingContainerTaskResponse\) === 'A0404'/)
|
|
assert.match(bridgeLoading, /push exact replay 对计划版本历史关联和任务零漂移/)
|
|
assert.match(bridgeLoading, /bookingConfirmed\?\.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 containerReleaseIndex = containerLoading.indexOf('订舱放舱为 RELEASED 且不预生成真实货柜')
|
|
const containerLinkIndex = containerLoading.indexOf('首次关联 RELEASED 订舱需求并补真实柜号')
|
|
const containerConfirmIndex = containerLoading.indexOf('计划级原子确认整份预装并触发唯一 PDA 任务')
|
|
const containerPdaIndex = containerLoading.indexOf('查询本轮柜次 PDA 拣货任务')
|
|
assert.ok(containerPushIndex >= 0 && containerReleaseIndex > containerPushIndex
|
|
&& containerLinkIndex > containerReleaseIndex
|
|
&& containerConfirmIndex > containerLinkIndex
|
|
&& 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 loading chain carries the three loading-list remarks contract', () => {
|
|
const loading = readFileSync(resolve(scriptsDir, 'admin-test-env-modules', 'phase3-loading.mjs'), 'utf8')
|
|
assert.match(adminAcceptance, /CONFIGURED_MODULES\s*=\s*\[[^\]]*'phase3-loading'/s)
|
|
assert.match(loading, /装柜明细客户备注与最新内部备注来源精确且不冒用货物备注/)
|
|
assert.match(loading, /warehouse-remark/)
|
|
assert.match(loading, /仓库备注相同 operationId 与原请求精确重放/)
|
|
assert.match(loading, /仓库备注旧版本冲突后版本与备注事实零漂移/)
|
|
assert.match(loading, /preservedRemarkItem\?\.warehouseRemark === warehouseRemark/)
|
|
})
|
|
|
|
test('default Admin HTTP entry completes settlement before customs consumes loaded slices', () => {
|
|
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-loading-finalize',
|
|
'phase3-customs',
|
|
])
|
|
|
|
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('focused order splitting completes the initial loading settlement first', () => {
|
|
const focused = normalizeModuleOrder(['phase3-order-splitting'])
|
|
const loading = focused.indexOf('phase3-loading')
|
|
const finalize = focused.indexOf('phase3-loading-finalize')
|
|
const splitting = focused.indexOf('phase3-order-splitting')
|
|
|
|
assert.ok(loading >= 0 && finalize > loading && splitting > finalize)
|
|
})
|
|
|
|
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'])
|
|
})
|