77 lines
4.4 KiB
JavaScript
77 lines
4.4 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
import { run } from './suppliers.mjs'
|
|
import { AcceptanceRun } from '../admin-test-env-acceptance.mjs'
|
|
const source=readFileSync(new URL('./suppliers.mjs',import.meta.url),'utf8')
|
|
const orchestrator=readFileSync(new URL('../admin-test-env-acceptance.mjs',import.meta.url),'utf8')
|
|
const openapi=readFileSync(new URL('../../warehouse/src/main/resources/openapi/supplier-v1.yaml',import.meta.url),'utf8')
|
|
|
|
test('supplier acceptance covers full CRUD-like lifecycle, carrier matrix and boundary failures',()=>{
|
|
for(const marker of ['列表分页与订舱筛选','查询四类供应商统计','新增供应商','查询供应商详情','编辑供应商','停用供应商','重复名称返回冲突','tenantId非0被拒绝','非BOOKING携带carrierCodes返回A0400并保留链路ID','客户账号调用平台供应商接口被拒绝','requestId','traceId']) assert.match(source,new RegExp(marker))
|
|
assert.match(source,/carrierCodes:\['MATSON','COSCO'\]/)
|
|
assert.match(source,/sameCarrierCodes\(detail\?\.carrierCodes,\['MATSON','COSCO'\]\)/)
|
|
assert.doesNotMatch(source,/scope\s*:/)
|
|
})
|
|
test('supplier module is registered in the default full acceptance orchestration',()=>assert.match(orchestrator,/CONFIGURED_MODULES = \[[^\]]*'suppliers'/s))
|
|
test('supplier fixture is retained only as inactive because API has no delete contract',()=>{assert.match(source,/finalStatus:inactive\?'INACTIVE'/);assert.doesNotMatch(source,/context\.request\('DELETE'/)})
|
|
test('supplier OpenAPI exposes the internal active category validation contract without scope',()=>{
|
|
for(const marker of ['/internal/warehouse/v1/suppliers/{supplierId}','X-Internal-Service-Token','requireActive','InternalSnapshot','SupplierPageResponse','platform:supplier:list']) assert.match(openapi,new RegExp(marker.replace(/[{}]/g,'\\$&')))
|
|
assert.doesNotMatch(openapi,/\bscope\b/)
|
|
assert.doesNotMatch(openapi,/platform:supplier:view/)
|
|
})
|
|
|
|
function existingHarness({ empty = false, wrongDetail = false, failStats = false } = {}) {
|
|
const runner = new AcceptanceRun({ environment: 'test', fixedCustomerId: '123', quiet: true })
|
|
const calls = []
|
|
const categories = ['BOOKING', 'CUSTOMS', 'TRUCKING', 'CERTIFICATE']
|
|
runner.request = async (method, path) => {
|
|
calls.push({ method, path })
|
|
assert.equal(method, 'GET', 'fixed suppliers must never mutate master data')
|
|
const url = new URL(path, 'http://offline.invalid')
|
|
let data
|
|
let code = '200'
|
|
if (url.searchParams.get('tenantId') === '1') code = 'A0400'
|
|
else if (url.pathname.endsWith('/stats')) {
|
|
data = { booking: 1, customs: 1, trucking: 1, certificate: 1 }
|
|
if (failStats) code = 'S0500'
|
|
} else if (url.searchParams.has('category')) {
|
|
const category = url.searchParams.get('category')
|
|
data = { records: empty ? [] : [{ id: String(categories.indexOf(category) + 1), category, status: 'ACTIVE' }],
|
|
page: 1, size: 20, total: empty ? 0 : 1, pages: empty ? 0 : 1 }
|
|
} else {
|
|
const id = url.pathname.split('/').at(-1)
|
|
data = { id, tenantId: wrongDetail ? '88' : '0', category: categories[Number(id) - 1], status: 'ACTIVE' }
|
|
}
|
|
return { http: 200, body: { code, data }, requestId: 'request', traceId: 'trace' }
|
|
}
|
|
return { runner, calls }
|
|
}
|
|
|
|
test('fixed supplier module runs through orchestrator using only existing read-only records', async () => {
|
|
const { runner, calls } = existingHarness()
|
|
await runner.executeModule('suppliers', () => run(runner))
|
|
assert.equal(calls.length, 10)
|
|
assert.equal(runner.modules[0].skipped, undefined)
|
|
assert.equal(runner.modules[0].success, true)
|
|
assert.equal(runner.coverageGaps.length, 1)
|
|
assert.equal(runner.coverageGaps[0].scenario, 'fixed-resource-lifecycle')
|
|
})
|
|
|
|
test('empty supplier lists retain detail gaps and never create replacements', async () => {
|
|
const { runner, calls } = existingHarness({ empty: true })
|
|
await run(runner)
|
|
assert.equal(calls.length, 6)
|
|
assert.equal(runner.coverageGaps.length, 5)
|
|
assert.ok(runner.steps.every(step => step.passed))
|
|
})
|
|
|
|
test('supplier detail scope drift and failed statistics remain failures', async () => {
|
|
for (const options of [{ wrongDetail: true }, { failStats: true }]) {
|
|
const { runner } = existingHarness(options)
|
|
await runner.executeModule('suppliers', () => run(runner))
|
|
assert.equal(runner.modules[0].success, false)
|
|
assert.ok(runner.steps.some(step => !step.passed))
|
|
}
|
|
})
|