64 lines
3.9 KiB
JavaScript
64 lines
3.9 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
|
|
const read = (path) => readFileSync(new URL(path, import.meta.url), 'utf8')
|
|
const adminPage = read('../../../apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingDetailView.vue')
|
|
const adminTypes = read('../../../apps/admin-web/src/modules/ocean-bookings/types.ts')
|
|
const prototype = read('../../../docs/悦/货代SAAS平台后台/prototype-src/modules/06-containers.html')
|
|
const dto = read('../../firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/dto/OceanBookingDtos.java')
|
|
const openapi = read('../../firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml')
|
|
const fixture = read('ocean-booking-fixture.mjs')
|
|
const booking = read('ocean-bookings.mjs')
|
|
const loading = read('phase3-container-loading.mjs')
|
|
const transportFields = ['billOfLadingNo', 'vesselName', 'voyageNo', 'estimatedSailingAt', 'estimatedArrivalAt']
|
|
|
|
test('prototype evidence keeps terms and optional customer while current DRAFT stays editable', () => {
|
|
assert.match(prototype, /主要运输条款 Service Term \*<\/label><select><option>CY-CY<\/option>/)
|
|
assert.match(prototype, /运费条款 Freight Term \*<\/label><select><option>NINGBO<\/option>/)
|
|
assert.match(prototype, /<label>客户\/公司名称<\/label><input id="booking-customer"/)
|
|
assert.match(adminPage, /const editable = computed\(\(\) => isNew\.value \|\| detail\.value\?\.status === 'DRAFT'\)/)
|
|
assert.match(adminTypes, /customerId:\s*string \| null;\s*customerName:\s*string \| null/)
|
|
assert.match(dto, /record DraftData\(@Positive Long customerId/)
|
|
assert.match(openapi, /customerId: \{[^\n]*nullable: true/)
|
|
})
|
|
|
|
test('DRAFT can be partial but release validates and freezes the five transport facts', () => {
|
|
assert.match(openapi, /description: Fields may be incomplete in DRAFT\. RELEASE validates the complete persisted aggregate/)
|
|
assert.match(openapi, /ReleaseRequest: \{type: object, required: \[expectedVersion\]/)
|
|
for (const field of transportFields) {
|
|
assert.match(adminPage, new RegExp(`form\\.data\\.${field}`), field)
|
|
assert.match(fixture, new RegExp(`${field}:`), field)
|
|
}
|
|
assert.match(booking, /const frozen = transportSnapshot\(completedDraft\?\.oceanBooking \|\| data\)/)
|
|
assert.match(booking, /documentType', 'BOOKING_CONFIRMATION'/)
|
|
assert.match(booking, /\/documents\/upload/)
|
|
assert.match(booking, /expectedVersion: documentVersion/)
|
|
assert.match(booking, /完整 DRAFT 放舱为 RELEASED 且冻结五项运输事实/)
|
|
assert.match(booking, /Object\.entries\(frozen\)\.every/)
|
|
assert.match(booking, /RELEASED 编辑拒绝且零写入/)
|
|
})
|
|
|
|
test('booking requirements replace booking-time real container rows', () => {
|
|
assert.match(openapi, /containerRequirements:/)
|
|
assert.match(openapi, /ContainerRequirementRequest: \{type: object, required: \[containerType, containerKind, quantity, capacityCbm, maxWeightKg\]/)
|
|
assert.match(fixture, /containerRequirements/)
|
|
assert.doesNotMatch(fixture, /containerNo|realContainerBookingId/)
|
|
assert.match(booking, /订舱创建返回 DRAFT 且只持久化柜型需求/)
|
|
assert.match(booking, /没有预生成货柜/)
|
|
})
|
|
|
|
test('port link supplies the real number and preserves current-marker customer isolation', () => {
|
|
assert.match(loading, /oceanBookingId: bookingId, requirementId: id\(requirement\.id\), containerNo: realContainerNo/)
|
|
assert.match(loading, /source\?\.marker !== context\.marker/)
|
|
assert.match(loading, /id\(candidate\?\.accountId\) === tenantId/)
|
|
assert.match(loading, /id\(item\.accountId\) === tenantId/)
|
|
assert.doesNotMatch(loading, /realContainerBookingId|MERGED/)
|
|
})
|
|
|
|
test('normal booking producers have only DRAFT and RELEASED lifecycle operations', () => {
|
|
assert.doesNotMatch(booking, /CHANGE_PENDING|CANCELLED|\/submit|\/confirm/)
|
|
assert.match(booking, /status === 'DRAFT'/)
|
|
assert.match(booking, /status === 'RELEASED'/)
|
|
})
|