Files
baiyue-firstleg/scripts/admin-test-env-modules/phase3-container-regression-contract.test.mjs
T

84 lines
4.9 KiB
JavaScript
Raw Normal View History

2026-08-14 14:26:56 +08:00
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
import { controlledPhotoDownload } from './phase3-container-overview.mjs'
const read = (path) => readFileSync(new URL(path, import.meta.url), 'utf8')
const overviewOpenApi = read('../../firstleg/src/main/resources/openapi/phase3-container-overview-v1.yaml')
const oceanOpenApi = read('../../firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml')
const overviewAcceptance = read('phase3-container-overview.mjs')
const oceanAcceptance = read('ocean-bookings.mjs')
const adminRoot = '../../../apps/admin-web/src/modules/'
const releaseView = read(`${adminRoot}ocean-bookings/pages/OceanBookingDetailView.vue`)
const releaseTypes = read(`${adminRoot}ocean-bookings/types.ts`)
const truckApi = read(`${adminRoot}trucking/api/platformTrucking.ts`)
const truckAttachmentDialog = read(`${adminRoot}trucking/components/TruckAttachmentDialog.vue`)
const truckList = read(`${adminRoot}trucking/pages/TruckAppointmentsView.vue`)
const truckForm = read(`${adminRoot}trucking/components/TruckAppointmentForm.vue`)
const containerList = read(`${adminRoot}container-loading/pages/ContainersView.vue`)
const containerLoadingAcceptance = read('phase3-container-loading.mjs')
const truckAcceptance = read('truck-appointments.mjs')
const matrix = read('../../../docs/三期/货柜管理全链验收矩阵-2026-08-13.md')
test('release request freezes all five transport fields and UI blocks incomplete submission', () => {
assert.match(oceanOpenApi, /required: \[expectedVersion, billOfLadingNo, vesselName, voyageNo, estimatedSailingAt, estimatedArrivalAt\]/)
for (const field of ['billOfLadingNo', 'vesselName', 'voyageNo', 'estimatedSailingAt', 'estimatedArrivalAt']) {
assert.match(releaseTypes, new RegExp(`${field}: string`), field)
assert.match(releaseView, new RegExp(`releaseForm\\.${field}`), field)
assert.match(oceanAcceptance, new RegExp(`${field}:`), field)
}
assert.match(releaseView, /if \(!billOfLadingNo \|\| !vesselName \|\| !voyageNo \|\| !releaseForm\.estimatedSailingAt \|\| !releaseForm\.estimatedArrivalAt\)/)
})
test('overview regression requires workflowStatus and distinguishes 100 percent awaiting review', () => {
assert.match(overviewAcceptance, /'workflowStatus'/)
assert.match(overviewAcceptance, /workflowStatus === 'AWAITING_REVIEW'/)
assert.match(overviewOpenApi, /workflowStatus:/)
assert.doesNotMatch(matrix, /PDA overview `workflowStatus` 缺失[\s\S]*BLOCKED_CONTRACT/)
})
test('every overview photo uses its server-provided controlled downloadPath', () => {
assert.match(overviewOpenApi, /\/api\/platform\/v1\/containers\/\{id\}\/pda\/photos\/\{fileId\}\/download/)
assert.match(overviewAcceptance, /context\.requestBinary\('GET', downloadPath\)/)
assert.equal(controlledPhotoDownload('/api/platform/v1/files/1', {
http: 200, bytes: new Uint8Array([1]), contentType: 'image/png',
}), true)
for (const [path, response] of [
['https://example.test/file', { http: 200, bytes: new Uint8Array([1]), contentType: 'image/png' }],
['/api/platform/v1/files/1', { http: 200, bytes: new Uint8Array([1]), contentType: 'application/json' }],
['/api/platform/v1/files/1', { http: 404, bytes: new Uint8Array(), contentType: 'image/png' }],
]) assert.equal(controlledPhotoDownload(path, response), false)
})
test('truck attachment API is frozen while Admin add-reference entry remains blocked', () => {
assert.match(truckApi, /referenceTruckAppointmentAttachment/)
assert.match(truckApi, /deleteTruckAppointmentAttachment/)
assert.doesNotMatch(truckAttachmentDialog, /referenceTruckAppointmentAttachment/)
assert.match(truckAcceptance, /删除后回查拖车预约附件列表/)
assert.match(truckAcceptance, /!remainingAttachments\.some/)
assert.match(matrix, /拖车附件新增入口缺失[\s\S]*BLOCKED_CONTRACT/)
})
test('existing container number replacement keeps container plan and PDA identities stable', () => {
assert.match(containerLoadingAcceptance, /replacementContainerNo/)
assert.match(containerLoadingAcceptance, /containerBookingId: containerId/)
assert.match(containerLoadingAcceptance, /loadingPlanId: planId/)
assert.match(containerLoadingAcceptance, /pdaTaskId: taskId/)
assert.match(containerLoadingAcceptance, /pdaIdentityStable: true/)
})
test('customer public display uses tenantName without a legalName fallback', () => {
for (const source of [truckList, containerList]) {
assert.match(source, /label: customer\.tenantName/)
}
assert.match(truckForm, /return customer\.tenantName/)
for (const source of [truckList, containerList, truckForm])
assert.doesNotMatch(source, /customer\.legalName\?\.trim\(\) \|\| customer\.tenantName/)
assert.match(matrix, /客户公开名称一致性[\s\S]*已统一 `tenantName`[\s\S]*`LANDED`/)
})
test('Chinese status dialogs and 390px layout remain explicit Admin contract blockers', () => {
assert.match(matrix, /中文状态、弹框与 390px 布局[\s\S]*BLOCKED_CONTRACT/)
})