Files
baiyue-firstleg/scripts/admin-test-env-modules/fixed-resource-readonly-contract.test.mjs
T
2026-11-04 18:08:19 +08:00

64 lines
3.6 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { AcceptanceRun } from '../admin-test-env-acceptance.mjs'
import { FIXED_RESOURCE_READONLY_MODULES } from './fixed-resource-readonly.mjs'
function runner(mutate = value => value) {
const context = new AcceptanceRun({ environment: 'test', fixedCustomerId: '123', quiet: true })
const calls = []
context.request = async (method, path) => {
calls.push({ method, path })
assert.equal(method, 'GET', '固定资源只读检查不得写入或创建资源')
let value = path.includes('?page=') ? { page: 1, size: 20, total: 0, records: [] } : []
if (path.endsWith('/tenants/123')) value = { id: '123', status: 'ACTIVE' }
if (path.endsWith('/dimension-initialization')) value = { status: 'READY' }
if (path.endsWith('/permissions')) value = [{ id: '1', permissionCode: 'platform:customer:list' }]
if (path.endsWith('/roles')) value = [{ id: '2', roleCode: 'EXISTING_ROLE' }]
if (path.includes('/iam/users?')) value.records = [{ membershipId: '3', tenantId: '0' }], value.total = 1
if (path.includes('/warehouse-admin?')) value.records = [{ id: '4', tenantId: '0' }], value.total = 1
return { method, path, http: 200, body: { code: '200', data: mutate(value, path) } }
}
return { context, calls }
}
for (const module of FIXED_RESOURCE_READONLY_MODULES) test(`${module}复用现有数据,只读通过且保留生命周期缺口`, async () => {
const { context, calls } = runner()
await context.executeModule(module, () => assert.fail('不得调用原生命周期处理器'))
const result = context.modules[0]
assert.equal(result.success, true)
assert.ok(result.passed > 0)
assert.equal(result.skipped, undefined)
assert.equal(result.coverageMode, 'READ_ONLY')
assert.equal(result.lifecycleSkipped, true)
assert.ok(calls.length > 0)
assert.ok(calls.every(row => row.method === 'GET'))
assert.equal(context.coverageGaps.length, 1)
assert.equal(context.coverageGaps[0].blocking, false)
assert.equal(context.createdResources.fixedResourceReadOnly[module].lifecycle, 'NOT_TESTED')
})
for (const [label, module, mutate] of [
['客户不匹配', 'customers', (value, path) => path.endsWith('/123') ? { ...value, id: '999' } : value],
['客户被停用', 'customers', (value, path) => path.endsWith('/123') ? { ...value, status: 'DISABLED' } : value],
['初始化未就绪', 'customers', (value, path) => path.endsWith('/dimension-initialization') ? { status: 'PENDING' } : value],
['仓库非公共归属', 'master-data', value => ({ ...value, records: [{ id: '4', tenantId: '999' }], total: 1 })],
['平台账号非平台归属', 'system', (value, path) => path.includes('/users?')
? { ...value, records: [{ membershipId: '3', tenantId: '123' }] } : value],
['分页结构缺失', 'notifications', () => []],
['分页范围错误', 'notifications', value => ({ ...value, page: 2 })],
['价格目录结构错误', 'pricing', () => ({ records: [] })],
]) test(`${label}必须失败,禁止补建或执行原写入处理器`, async () => {
const { context, calls } = runner(mutate)
await context.executeModule(module, () => assert.fail('不能回退创建数据'))
assert.equal(context.modules[0].success, false)
assert.ok(context.modules[0].failed > 0)
assert.ok(calls.every(row => row.method === 'GET'))
})
test('权限错误保留为真实失败,不以空目录通过', async () => {
const { context } = runner()
context.request = async () => ({ http: 403, body: { code: 'A0403' } })
await context.executeModule('system', () => assert.fail('不能修改授权'))
assert.equal(context.modules[0].success, false)
})