2026-08-24 21:00:22 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import test from 'node:test'
|
|
|
|
|
|
2026-09-30 12:58:15 +08:00
|
|
|
import { loadingBookingCustomerFields, markerSuffix } from './phase3-loading.mjs'
|
|
|
|
|
import { withPlatformBookingScope } from './phase3-container-customs-fixture.mjs'
|
|
|
|
|
|
|
|
|
|
test('normal loading keeps customer scope; explicit platform booking omits both customer fields', () => {
|
|
|
|
|
const fields = loadingBookingCustomerFields(undefined, '2100000000000000001', '测试客户')
|
|
|
|
|
assert.deepEqual(fields, { customerId: '2100000000000000001', customerName: '测试客户' })
|
|
|
|
|
assert.deepEqual(loadingBookingCustomerFields('CUSTOMER', fields.customerId, fields.customerName), fields)
|
|
|
|
|
const platform = loadingBookingCustomerFields('PLATFORM', fields.customerId, fields.customerName)
|
|
|
|
|
assert.equal(Object.hasOwn(platform, 'customerId'), false)
|
|
|
|
|
assert.equal(Object.hasOwn(platform, 'customerName'), false)
|
|
|
|
|
assert.throws(() => loadingBookingCustomerFields('MISSPELLED', fields.customerId, fields.customerName), /订舱范围/)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('mixed fixture platform scope restores absence and an existing value after success or failure', async () => {
|
|
|
|
|
const absent = { context: {} }
|
|
|
|
|
assert.equal(await withPlatformBookingScope(absent, async () => {
|
|
|
|
|
assert.equal(absent.context.phase3LoadingBookingScope, 'PLATFORM')
|
|
|
|
|
return 'loaded'
|
|
|
|
|
}), 'loaded')
|
|
|
|
|
assert.equal(Object.hasOwn(absent.context, 'phase3LoadingBookingScope'), false)
|
|
|
|
|
const existing = { context: { phase3LoadingBookingScope: 'CUSTOMER' } }
|
|
|
|
|
await assert.rejects(withPlatformBookingScope(existing, async () => {
|
|
|
|
|
assert.equal(existing.context.phase3LoadingBookingScope, 'PLATFORM')
|
|
|
|
|
throw new Error('actual loading failure')
|
|
|
|
|
}), /actual loading failure/)
|
|
|
|
|
assert.equal(existing.context.phase3LoadingBookingScope, 'CUSTOMER')
|
|
|
|
|
})
|
2026-08-24 21:00:22 +08:00
|
|
|
|
|
|
|
|
test('phase3 loading fixture identifiers are deterministic and distinct across marker variants', () => {
|
|
|
|
|
const base = 'ADMIN-API-20260824123024536'
|
|
|
|
|
const primary = markerSuffix(`${base}-P4-OVERSEAS-PRIMARY`)
|
|
|
|
|
const secondary = markerSuffix(`${base}-P4-SECONDARY`)
|
|
|
|
|
|
|
|
|
|
assert.equal(primary, markerSuffix(`${base}-P4-OVERSEAS-PRIMARY`))
|
|
|
|
|
assert.notEqual(primary, secondary)
|
|
|
|
|
assert.match(primary, /^\d{8}-[0-9A-F]{8}$/)
|
|
|
|
|
assert.ok(`P3B-${primary}`.length <= 64)
|
|
|
|
|
})
|
2026-08-24 21:46:19 +08:00
|
|
|
|
2026-09-04 15:19:45 +08:00
|
|
|
test('phase3 loading uses the collision-safe marker suffix for generated business identifiers', async () => {
|
2026-08-24 21:46:19 +08:00
|
|
|
const source = await import('node:fs/promises').then((fs) => fs.readFile(
|
|
|
|
|
new URL('./phase3-loading.mjs', import.meta.url), 'utf8'))
|
2026-09-04 15:19:45 +08:00
|
|
|
assert.match(source, /const suffix = markerSuffix\(context\.marker\)/)
|
2026-09-30 12:58:15 +08:00
|
|
|
assert.match(source, /const bookingDraft = \{\s*\.\.\.loadingBookingCustomerFields\(context\.context\?\.phase3LoadingBookingScope, tenantId,/)
|
2026-09-04 15:19:45 +08:00
|
|
|
assert.match(source, /billOfLadingNo: `P3BL-\$\{suffix\}`/)
|
|
|
|
|
assert.match(source, /vesselName: `P3VESSEL-\$\{suffix\}`/)
|
|
|
|
|
assert.doesNotMatch(source, /suffix = context\.marker\.replace\(\/\\D\/g/)
|
|
|
|
|
assert.match(source, /增量后旧 inventory token 明确 A0409 并要求刷新/)
|
|
|
|
|
assert.match(source, /增量旧 token 冲突后 plan\/task\/items 零写入/)
|
2026-08-24 21:46:19 +08:00
|
|
|
})
|