Files
baiyue-firstleg/scripts/admin-test-env-modules/manual-state-matrix.mjs
T
2026-10-08 17:07:57 +08:00

133 lines
6.9 KiB
JavaScript

const MODULE = 'manual-state-matrix'
const OPTIONS = { scenario: 'manual-clickable-list-state-matrix', deploymentBlocker: true }
const GROUPS = [
'order-inbound-status-fixtures',
'manual-state-loading-pda',
'manual-state-ocean-trucking',
]
const FIXTURE_UNAVAILABLE = {
inbounds: {
MEASURE_REJECTED: '当前稳定 Admin 契约未开放测量审核驳回接口,无法稳定构造该状态',
INBOUNDING: '当前公开接口没有可独立保留的 INBOUNDING 生成或暂停链路;不通过写业务SQL伪造中间状态',
VOIDED: '当前 Controller/Service 没有作废入库单的公开 API',
},
}
function rows(value) { return Array.isArray(value) ? value : [] }
function id(value) { return value == null ? '' : String(value) }
export function normalizeStateRequirements(matrix) {
for (const [page, value] of Object.entries(matrix?.pages || {})) {
const supportedStatuses = [...new Set([
...rows(value?.supportedStatuses), ...rows(value?.requiredStatuses),
])]
const unavailable = FIXTURE_UNAVAILABLE[page] || {}
value.supportedStatuses = supportedStatuses
value.requiredStatuses = supportedStatuses.filter((status) => !unavailable[status])
if (Object.keys(unavailable).length > 0) {
value.coverageGaps = Object.fromEntries(Object.entries(unavailable).map(([status, reason]) => [status, {
category: 'fixture-unavailable', reason,
}]))
}
}
return matrix
}
export function missingRequiredStateFixtures(matrix) {
return Object.entries(matrix?.pages || {}).flatMap(([page, value]) => rows(value?.requiredStatuses)
.filter((status) => !value?.fixtures?.[status]?.id)
.map((status) => `${page}:${status}`))
}
export async function attachDeliveredOrderFixture(context, matrix) {
const fulfilled = context.createdResources?.phase5OverseasFulfillment
const proof = fulfilled?.orderCompletionProof
const customerId = id(proof?.customerId)
const orderId = id(proof?.rootOrderId)
if (fulfilled?.marker !== context.marker || !customerId || !orderId || !proof?.rootDelivered || proof.expectedCompleted !== false) {
throw new Error('DELIVERED 样本须复用本轮已签收且仍有有效余量的履约根')
}
const response = await context.request('GET',
`/api/platform/v1/orders/${encodeURIComponent(orderId)}?tenantId=${encodeURIComponent(customerId)}`)
const detail = context.apiSuccess(MODULE, '回读真实签收产生的 DELIVERED 统一订单', response, '', OPTIONS)
const valid = id(detail?.summary?.orderId) === orderId && detail?.summary?.mainStatus === 'DELIVERED'
context.assert(MODULE, 'DELIVERED 样本客户与真实根签收状态正确', response, valid,
`orderId=${orderId}, status=${detail?.summary?.mainStatus || 'missing'}`, OPTIONS)
if (!valid) throw new Error('DELIVERED 履约根详情未收敛到真实签收状态')
matrix.pages.unifiedOrders.fixtures.DELIVERED = { id: orderId, status: 'DELIVERED',
customerId, detailPath: `/orders/${orderId}` }
}
function registerFixtureUnavailableGaps(context, matrix) {
for (const [page, value] of Object.entries(matrix?.pages || {})) {
for (const [status, gap] of Object.entries(value?.coverageGaps || {})) {
if (value?.fixtures?.[status]?.id) continue
if (rows(context.coverageGaps).some((item) => item?.category === gap.category
&& String(item?.name || '').includes(status))) continue
context.addCoverageGap?.(MODULE, OPTIONS.scenario, `${page}:${status}`, gap.reason,
gap.category, { marker: context.marker, page, status, blocking: false })
}
}
}
async function attachUnifiedOrderFixture(context, matrix, resourceName, expectedStatus) {
const resource = context.createdResources?.[resourceName]
const inboundId = id(resource?.inboundId)
const tenantId = id(resource?.tenantId)
context.assert(MODULE, `${expectedStatus} 专项资源已生成`, null,
Boolean(inboundId && tenantId),
`resource=${resourceName}, inboundId=${inboundId || 'missing'}, tenantId=${tenantId || 'missing'}`, OPTIONS)
if (!inboundId || !tenantId) return
const inboundResponse = await context.request('GET',
`/api/platform/inbounds/${encodeURIComponent(inboundId)}?tenantId=${encodeURIComponent(tenantId)}`)
const inbound = context.apiSuccess(MODULE, `读取 ${expectedStatus} 专项入库详情`, inboundResponse, '', OPTIONS)
const orderId = id(inbound?.summary?.orderId)
context.assert(MODULE, `${expectedStatus} 入库详情身份与状态正确`, inboundResponse,
id(inbound?.summary?.id) === inboundId && id(inbound?.summary?.tenantId) === tenantId
&& Boolean(orderId) && inbound?.summary?.processStatus === expectedStatus,
`inboundId=${id(inbound?.summary?.id) || 'missing'}, orderId=${orderId || 'missing'}, status=${inbound?.summary?.processStatus || 'missing'}`, OPTIONS)
if (!orderId || inbound?.summary?.processStatus !== expectedStatus) return
const unifiedResponse = await context.request('GET',
`/api/platform/v1/orders/${encodeURIComponent(orderId)}?tenantId=${encodeURIComponent(tenantId)}`)
const unified = context.apiSuccess(MODULE, `读取 ${expectedStatus} 统一订单详情`, unifiedResponse, '', OPTIONS)
const valid = id(unified?.summary?.orderId) === orderId && unified?.summary?.mainStatus === expectedStatus
context.assert(MODULE, `${expectedStatus} 统一订单详情可打开`, unifiedResponse, valid,
`orderId=${id(unified?.summary?.orderId) || 'missing'}, mainStatus=${unified?.summary?.mainStatus || 'missing'}`, OPTIONS)
if (!valid) return
matrix.pages.unifiedOrders.fixtures[expectedStatus] = {
id: orderId, status: expectedStatus, inboundId,
detailPath: `/orders/${orderId}`,
}
}
export async function run(context) {
const matrix = { marker: context.marker, generatedAt: new Date().toISOString(), pages: {} }
context.createdResources.manualStateMatrix = matrix
for (const name of GROUPS) {
const extension = await import(new URL(`./${name}.mjs`, import.meta.url))
if (typeof extension.run !== 'function') throw new Error(`${name} 必须导出 async function run(context)`)
await extension.run(context, matrix)
}
await attachUnifiedOrderFixture(context, matrix, 'phase3Loading', 'LOADED')
await attachDeliveredOrderFixture(context, matrix)
normalizeStateRequirements(matrix)
registerFixtureUnavailableGaps(context, matrix)
const pages = Object.entries(matrix.pages)
const missing = missingRequiredStateFixtures(matrix)
const missingActions = pages.flatMap(([page, value]) => rows(value?.requiredActions)
.filter((action) => !value?.actions?.[action]?.id
|| !value?.actions?.[action]?.documentId || !value?.actions?.[action]?.completedAt)
.map((action) => `${page}:action:${action}`))
context.assert(MODULE, '人工验收列表状态数据全部生成并保留', null,
pages.length > 0 && missing.length === 0 && missingActions.length === 0,
`pages=${pages.length}, missing=${[...missing, ...missingActions].join(',') || 'none'}`, OPTIONS)
}