This commit is contained in:
2026-10-21 21:30:24 +08:00
parent 234216b3eb
commit 5356a8c898
28 changed files with 1543 additions and 45 deletions
@@ -7,6 +7,28 @@ import { inflateRawSync, deflateRawSync } from 'node:zlib'
const source = await readFile(new URL('./client-test-env-acceptance.mjs', import.meta.url), 'utf8')
test('fixed Client authenticates and verifies ownership without registration', async () => {
const calls = []
const scope = vm.createContext({ username: 'fixture', clientPassword: 'test-password', fixedCustomerId: '123',
report: { resources: {} }, assertEqual: assert.equal,
requireSuccess: json => assert.equal(json.code, 200), assertPresent: assert.ok,
async apiStep(_module, _name, request, validate) {
calls.push(request)
const json = { code: 200, data: request.path.endsWith('/login')
? { accessToken: 'test-token', refreshToken: 'test-refresh' }
: { id: '123', status: 'ACTIVE', tenantName: 'Fixture' } }
validate({ json }); return { json }
},
})
const helper = source.slice(source.indexOf('async function reuseFixedClient()'), source.indexOf('async function registrationModule()'))
vm.runInContext(`let merchantToken, merchantRefreshToken, companyName; ${helper}`, scope)
await scope.reuseFixedClient()
assert.deepEqual(calls.map(call => call.path), ['/api/auth/login', '/api/merchant/v1/iam/tenant/profile'])
assert.equal(scope.report.resources.tenantId, '123')
scope.fixedCustomerId = '456'
await assert.rejects(scope.reuseFixedClient(), /fixed customer identity/)
})
test('client registration distinguishes incomplete-registration replay from credential conflicts', () => {
assert.match(source, /same credentials replay the incomplete registration/)
assert.match(source, /\['accountId', 'tenantId', 'membershipId'\]/)
@@ -510,12 +532,12 @@ test('F01 client bills module covers customer-only read APIs and rejects unknown
assert.match(source, /async function merchantFinanceBillsModule\(\)/)
assert.match(source, /await merchantFinanceBillsModule\(\)/)
const callOrder = [
source.indexOf('await orderSubmissionChannelGateModule()'),
source.indexOf('await orderExcelImportModule()'),
source.indexOf('await merchantFinanceBillsModule()'),
source.indexOf('await notificationInboxModule()'),
source.indexOf('await merchantOverseasWarehouseModule()'),
]
assert.ok(callOrder[0] >= 0 && callOrder[1] > callOrder[0] && callOrder[2] > callOrder[1],
'bills module must run after channel gate and before notifications')
'fixed customer bills module runs after orders and before overseas queries')
assert.match(source, /const base = '\/api\/client\/finance\/v1'/)
for (const path of ['/bills', '/statements', '/receipts', '/receivable-settlements', '/confirm']) {
assert.ok(source.includes(path), path)
@@ -535,10 +557,10 @@ test('F02 client overseas self-service covers customer-scoped lists and the retu
const callOrder = [
source.indexOf('await merchantFinanceBillsModule()'),
source.indexOf('await merchantOverseasWarehouseModule()'),
source.indexOf('await notificationInboxModule()'),
source.indexOf('await merchantCrossBorderModule()'),
]
assert.ok(callOrder[0] >= 0 && callOrder[1] > callOrder[0] && callOrder[2] > callOrder[1],
'overseas self-service must run after bills and before notifications')
'overseas self-service runs after bills and before cross-border flow')
for (const path of ['/api/merchant/v1/warehouses', '/return-orders', '/relabel-applications',
'/warehouse-transfers', '/cargo-discards', '/return-inventory', '/return-inventory/summary',
'/return-inventory/cartons']) {
@@ -559,10 +581,10 @@ test('F03 client cross-border, warehouse orders and pricing/customs cover curren
assert.match(source, new RegExp(`await ${name}\\(\\)`), name)
}
const order = ['merchantOverseasWarehouseModule', 'merchantCrossBorderModule',
'merchantWarehouseOrdersModule', 'merchantPricingCustomsModule', 'notificationInboxModule']
'merchantWarehouseOrdersModule', 'merchantPricingCustomsModule']
.map((name) => source.indexOf(`await ${name}()`))
assert.ok(order.every((index) => index >= 0) && order.every((index, position) => position === 0 || index > order[position - 1]),
'new client modules must run in order before notifications')
'fixed customer business modules preserve their dependency order')
for (const path of ['/us-truck-orders', '/local-looseboard-orders', '/overseas-procurements',
'/inbound-plans', '/delivery-orders', '/first-leg/pricing/channels', '/customs/pending-summary',
'/customs/orders/']) {