This commit is contained in:
2026-10-22 14:37:59 +08:00
parent de96e47d74
commit 760bf8daa1
49 changed files with 2450 additions and 117 deletions
@@ -1,6 +1,8 @@
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')
@@ -18,3 +20,57 @@ test('supplier OpenAPI exposes the internal active category validation contract
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))
}
})