test: stabilize full dev acceptance orchestration
This commit is contained in:
@@ -19,37 +19,6 @@ function operationId(context, label) {
|
||||
return `${context.marker}-manual-loading-${label}-${crypto.randomUUID()}`.slice(0, 128)
|
||||
}
|
||||
|
||||
async function post(context, path, body, label) {
|
||||
return context.request('POST', path, body, context.token,
|
||||
{ 'Idempotency-Key': operationId(context, label) })
|
||||
}
|
||||
|
||||
async function uploadDocument(context, path, expectedVersion, operationReason, label) {
|
||||
const form = new FormData()
|
||||
form.append('file', new Blob([`${context.marker}-${label}`], { type: 'text/plain' }), `${label}.txt`)
|
||||
form.append('expectedVersion', String(expectedVersion))
|
||||
if (operationReason) form.append('operationReason', operationReason)
|
||||
try {
|
||||
const response = await fetch(`${context.options.gateway}${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json', Authorization: `Bearer ${context.token}`,
|
||||
'Idempotency-Key': operationId(context, `${label}-upload`),
|
||||
},
|
||||
body: form,
|
||||
signal: AbortSignal.timeout(60_000),
|
||||
})
|
||||
const raw = await response.text()
|
||||
let body = null
|
||||
try { body = raw ? JSON.parse(raw) : null } catch { /* bounded raw evidence */ }
|
||||
return { method: 'POST', path, http: response.status, body, raw: body ? null : raw.slice(0, 500),
|
||||
requestId: body?.requestId || response.headers.get('x-request-id'),
|
||||
traceId: body?.traceId || response.headers.get('x-trace-id') }
|
||||
} catch (error) {
|
||||
return { method: 'POST', path, http: 0, body: null, raw: String(error), requestId: null, traceId: null }
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureCompletionEvidence(context, chain, label) {
|
||||
const taskId = id(chain.task?.id)
|
||||
const warehouseId = id(chain.source?.warehouseId)
|
||||
@@ -351,34 +320,26 @@ function fixture(value, status, detailPath, extra = {}) {
|
||||
return { id: id(value), status, detailPath, ...extra }
|
||||
}
|
||||
|
||||
async function completeSimpleDocuments(context, chain, matrix) {
|
||||
const reason = `${context.marker} 人工页面动作验收`
|
||||
const clearancePath = `${CONTAINERS}/${chain.containerId}/clearance`
|
||||
const clearanceUpload = await uploadDocument(context, `${clearancePath}/document/upload`, 0,
|
||||
reason, 'container-clearance')
|
||||
const clearanceDocument = context.apiSuccess(MODULE, '货柜公开接口上传目的港清关资料',
|
||||
clearanceUpload, '', OPTIONS)
|
||||
context.assert(MODULE, '货柜清关上传返回真实文件事实', clearanceUpload,
|
||||
Boolean(clearanceDocument?.id) && Boolean(clearanceDocument?.fileId)
|
||||
&& clearanceDocument?.documentType === 'DESTINATION_CLEARANCE'
|
||||
&& /^[0-9a-f]{64}$/i.test(String(clearanceDocument?.fileHash || ''))
|
||||
&& !clearanceDocument?.completedAt,
|
||||
`documentId=${id(clearanceDocument?.id) || 'missing'}, version=${clearanceDocument?.version ?? 'missing'}`, OPTIONS)
|
||||
if (!clearanceDocument?.id || !clearanceDocument?.fileId || !Number.isInteger(Number(clearanceDocument?.version))) return
|
||||
const clearanceCompleteResponse = await post(context, `${clearancePath}/complete`, {
|
||||
expectedVersion: Number(clearanceDocument?.version), operationReason: reason,
|
||||
}, 'container-clearance-complete')
|
||||
const clearanceCompleted = context.apiSuccess(MODULE, '货柜点击完成目的港清关',
|
||||
clearanceCompleteResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '货柜清关完成事实可回读', clearanceCompleteResponse,
|
||||
id(clearanceCompleted?.id) === id(clearanceDocument?.id) && Boolean(clearanceCompleted?.completedAt)
|
||||
&& Number(clearanceCompleted?.version) === Number(clearanceDocument?.version) + 1,
|
||||
`documentId=${id(clearanceCompleted?.id) || 'missing'}, completedAt=${clearanceCompleted?.completedAt || 'missing'}`, OPTIONS)
|
||||
async function registerClearanceAction(context, matrix) {
|
||||
const documentsFixture = context.createdResources?.phase3ContainerDocuments
|
||||
const containerId = id(documentsFixture?.containerBookingId)
|
||||
const expectedDocumentId = id(documentsFixture?.documentIds?.DESTINATION_CLEARANCE)
|
||||
context.assert(MODULE, '复用本轮离仓后已完成的目的港清关动作', null,
|
||||
documentsFixture?.marker === context.marker && Boolean(containerId && expectedDocumentId),
|
||||
`containerBookingId=${containerId || 'missing'}, documentId=${expectedDocumentId || 'missing'}`, OPTIONS)
|
||||
if (!containerId || !expectedDocumentId || documentsFixture?.marker !== context.marker) return
|
||||
|
||||
matrix.pages.containerLoading.actions = { clearance: fixture(chain.containerId, 'COMPLETED',
|
||||
`/container-loading/${chain.containerId}/smart-loading`, {
|
||||
documentId: id(clearanceCompleted?.id), documentVersion: Number(clearanceCompleted?.version),
|
||||
completedAt: clearanceCompleted?.completedAt || null,
|
||||
const response = await context.request('GET', `${CONTAINERS}/${containerId}/clearance`)
|
||||
const completed = context.apiSuccess(MODULE, '回读目的港清关动作验收事实', response, '', OPTIONS)
|
||||
context.assert(MODULE, '目的港清关动作保持完成和版本事实', response,
|
||||
id(completed?.id) === expectedDocumentId && completed?.documentType === 'DESTINATION_CLEARANCE'
|
||||
&& Boolean(completed?.completedAt) && Number.isInteger(Number(completed?.version)),
|
||||
`documentId=${id(completed?.id) || 'missing'}, completedAt=${completed?.completedAt || 'missing'}, version=${completed?.version ?? 'missing'}`, OPTIONS)
|
||||
|
||||
matrix.pages.containerLoading.actions = { clearance: fixture(containerId, 'COMPLETED',
|
||||
`/container-loading/${containerId}/smart-loading`, {
|
||||
documentId: id(completed?.id), documentVersion: Number(completed?.version),
|
||||
completedAt: completed?.completedAt || null,
|
||||
}) }
|
||||
}
|
||||
|
||||
@@ -464,6 +425,6 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
id(listDetail?.summary?.planId) === listFixture.id && listDetail?.summary?.status === 'COMPLETED',
|
||||
`planId=${listFixture.id}, actual=${listDetail?.summary?.status || 'missing'}`, OPTIONS)
|
||||
|
||||
await completeSimpleDocuments(context, completed, matrix)
|
||||
await registerClearanceAction(context, matrix)
|
||||
}
|
||||
import { iso6346ContainerNumber } from './iso6346-container-number.mjs'
|
||||
|
||||
Reference in New Issue
Block a user