91 lines
5.3 KiB
JavaScript
91 lines
5.3 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { verifyPermissionDenial } from './domestic-container.mjs'
|
|
|
|
test('fixed denial actor never creates, resets or disables accounts and always logs out', async () => {
|
|
for (const deniedCode of ['A0403', '200']) {
|
|
const calls = []
|
|
const actor = { membershipId: '123', username: 'deny-fixture', password: 'fixture-password' }
|
|
const context = { options: { fixedCustomerId: '456', fixedDomesticDenyActor: actor },
|
|
async request(method, path) {
|
|
calls.push({ method, path })
|
|
const data = path.includes('/iam/users?') ? { total: 1, records: [{ ...actor, tenantId: '0', status: 'ACTIVE' }] }
|
|
: path === '/api/auth/login' ? { accessToken: 'fixture-token', refreshToken: 'fixture-refresh' } : {}
|
|
return { http: 200, body: { code: path.includes('/inventories?') ? deniedCode : '200', data }, requestId: 'test', traceId: 'test' }
|
|
}, apiSuccess(_module, _label, response) { return response.body.data }, assert() {},
|
|
}
|
|
if (deniedCode === 'A0403') await verifyPermissionDenial(context, 'RUN', '789', 'CONTAINER')
|
|
else await assert.rejects(verifyPermissionDenial(context, 'RUN', '789', 'CONTAINER'), /实际权限不符/)
|
|
assert.equal(calls.at(-1).path, '/api/auth/logout')
|
|
assert.ok(calls.every(call => call.method === 'GET' || ['/api/auth/login', '/api/auth/logout'].includes(call.path)))
|
|
}
|
|
})
|
|
|
|
test('missing fixed denial account blocks without requesting a phone or making HTTP calls', async () => {
|
|
await assert.rejects(verifyPermissionDenial({ options: { fixedCustomerId: '123' } }, 'RUN', '789', 'CONTAINER'), /禁止自动创建/)
|
|
})
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url))
|
|
const moduleSource = fs.readFileSync(path.join(here, 'domestic-container.mjs'), 'utf8')
|
|
const acceptance = fs.readFileSync(path.join(here, '..', 'admin-test-env-acceptance.mjs'), 'utf8')
|
|
|
|
test('国内整柜模块仅由总编排注入 context 后执行', () => {
|
|
assert.match(moduleSource, /export async function run\(context\)/)
|
|
assert.doesNotMatch(moduleSource, /https?:\/\//)
|
|
assert.doesNotMatch(moduleSource, /ADMIN_TEST_GATEWAY|process\.env|fetch\(/)
|
|
assert.match(acceptance, /import\(new URL\(`\.\/admin-test-env-modules\/\$\{module\}\.mjs`/)
|
|
})
|
|
|
|
test('正式全量验收默认注册国内整柜模块', () => {
|
|
assert.match(acceptance, /CONFIGURED_MODULES\s*=\s*\[[^\]]*['"]domestic-container['"]/s)
|
|
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/)
|
|
})
|
|
|
|
test('覆盖国内仓、待单、完成入库、部分和全部出库及列表详情流水', () => {
|
|
for (const token of ['warehouseType=DOMESTIC', "status: 'PENDING'", "status: 'COMPLETED'",
|
|
'PARTIALLY_OUTBOUND', "inventoryStatus === 'OUTBOUND'", '/inbounds?page=1', '/outbounds?page=1',
|
|
'/inventories/${inventoryId}', 'transactions?.length === 3']) assert.match(moduleSource, new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')))
|
|
})
|
|
|
|
test('在创建测试数据前覆盖无筛选整柜入库列表', () => {
|
|
const unfilteredList = '`${BASE}/inbounds?page=1&size=20`'
|
|
const runSource = moduleSource.slice(moduleSource.indexOf('export async function run(context)'))
|
|
assert.match(moduleSource, /无筛选查询整柜入库单列表/)
|
|
assert.ok(runSource.indexOf(unfilteredList) < runSource.indexOf("api(context, 'POST', `${BASE}/inbounds`"))
|
|
})
|
|
|
|
test('覆盖库存不足、版本冲突及两类幂等行为', () => {
|
|
assert.match(moduleSource, /库存不足禁止出库/)
|
|
assert.match(moduleSource, /过期库存版本冲突/)
|
|
assert.match(moduleSource, /同幂等键同请求重放/)
|
|
assert.match(moduleSource, /同幂等键不同请求冲突/)
|
|
assert.match(moduleSource, /inventoryVersion/)
|
|
})
|
|
|
|
test('覆盖权限拒绝与 requestId traceId', () => {
|
|
assert.match(moduleSource, /无整柜权限用户被拒绝/)
|
|
assert.match(moduleSource, /'A0403'/)
|
|
assert.match(moduleSource, /Boolean\(response\?\.requestId\).*Boolean\(response\?\.traceId\)/s)
|
|
assert.match(moduleSource, /status: 'DISABLED'/)
|
|
})
|
|
|
|
test('扩展覆盖字段边界、组合筛选、标准化、分页汇总和详情不存在', () => {
|
|
for (const token of ['集装箱号格式非法被拒绝', '零箱入库被拒绝', '零体积入库被拒绝',
|
|
'非法入库状态被拒绝', '空幂等键被拒绝', '超长备注被拒绝', '非法入库分页大小被拒绝',
|
|
'非法库存状态筛选被拒绝', '同仓同柜同货名追加入库', '同仓同柜不同货名禁止合并库存',
|
|
'筛选汇总不受分页大小影响且柜号已标准化', '入库单筛选总数与分页记录正确',
|
|
'不存在的整柜库存详情返回未找到']) assert.match(moduleSource, new RegExp(token))
|
|
})
|
|
|
|
test('扩展覆盖强制库存版本、并发竞争和成功请求幂等重放', () => {
|
|
assert.match(moduleSource, /完成出库必须携带库存版本/)
|
|
assert.match(moduleSource, /缺失库存版本的请求不得扣减库存/)
|
|
assert.match(moduleSource, /Promise\.all\(raceBodies\.map/)
|
|
assert.match(moduleSource, /同一库存版本并发出库仅一个成功/)
|
|
assert.match(moduleSource, /并发出库只扣减一次并只新增一条流水/)
|
|
assert.match(moduleSource, /并发成功请求重放不重复扣减/)
|
|
})
|