From dbca4a14030cc06aaf772599ede8af410781e5f8 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 14 Aug 2026 21:37:02 +0800 Subject: [PATCH] test: stop container acceptance after failed booking link --- .../phase3-container-loading.mjs | 23 +++++++++++++++---- .../phase3-producer-chain-contract.test.mjs | 12 ++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/scripts/admin-test-env-modules/phase3-container-loading.mjs b/scripts/admin-test-env-modules/phase3-container-loading.mjs index 832e42614..a91efae16 100644 --- a/scripts/admin-test-env-modules/phase3-container-loading.mjs +++ b/scripts/admin-test-env-modules/phase3-container-loading.mjs @@ -9,6 +9,9 @@ const FIRST_LEG = '/api/platform/v1/first-leg' function id(value) { return value == null ? '' : String(value) } function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) } +function responseEvidence(response) { + return `HTTP=${response?.http ?? 'missing'}, code=${codeOf(response)}, requestId=${response?.requestId || 'missing'}, traceId=${response?.traceId || 'missing'}` +} function failure(response) { return [400, 401, 403, 404, 409, 503].includes(response?.http) || (response?.http === 200 && codeOf(response) !== '200') @@ -284,25 +287,35 @@ export async function run(context) { const emptyLink = await request(context, 'POST', `${CONTAINERS}/${emptyContainerId}/ocean-booking-link`, { oceanBookingId: bookingId, requirementId: id(requirement.id), expectedVersion: Number(emptySimulation.version), }) - emptySimulation = context.apiSuccess(MODULE, '空模拟柜首次关联真实订舱', emptyLink, '', OPTIONS) + emptySimulation = context.apiSuccess(MODULE, '空模拟柜首次关联真实订舱', emptyLink, + responseEvidence(emptyLink), OPTIONS) + if (!emptySimulation) return const emptyUnlink = await request(context, 'DELETE', `${CONTAINERS}/${emptyContainerId}/ocean-booking-link`, { expectedVersion: Number(emptySimulation.version), reason: context.marker, }) - emptySimulation = context.apiSuccess(MODULE, '空模拟柜允许解除关联', emptyUnlink, '', OPTIONS) + emptySimulation = context.apiSuccess(MODULE, '空模拟柜允许解除关联', emptyUnlink, + responseEvidence(emptyUnlink), OPTIONS) + if (!emptySimulation) return const emptyRelink = await request(context, 'POST', `${CONTAINERS}/${emptyContainerId}/ocean-booking-link`, { oceanBookingId: bookingId, requirementId: id(requirement.id), expectedVersion: Number(emptySimulation.version), }) - emptySimulation = context.apiSuccess(MODULE, '空模拟柜解绑后允许重新关联', emptyRelink, '', OPTIONS) + emptySimulation = context.apiSuccess(MODULE, '空模拟柜解绑后允许重新关联', emptyRelink, + responseEvidence(emptyRelink), OPTIONS) + if (!emptySimulation) return const emptyFinalUnlink = await request(context, 'DELETE', `${CONTAINERS}/${emptyContainerId}/ocean-booking-link`, { expectedVersion: Number(emptySimulation.version), reason: `${context.marker}-release-capacity`, }) - context.apiSuccess(MODULE, '空模拟柜最终解绑释放真实订舱容量', emptyFinalUnlink, '', OPTIONS) + const emptyReleased = context.apiSuccess(MODULE, '空模拟柜最终解绑释放真实订舱容量', emptyFinalUnlink, + responseEvidence(emptyFinalUnlink), OPTIONS) + if (!emptyReleased) return const beforeLinkItems = JSON.stringify(assigned.items?.map((item) => ({ id: id(item.id), inboundId: id(item.inboundId), packageCount: Number(item.packageCount) })) || []) const linkResponse = await request(context, 'POST', `${CONTAINERS}/${containerId}/ocean-booking-link`, { oceanBookingId: bookingId, requirementId: id(requirement.id), expectedVersion: Number(containerDetail.version), }) - const linkedContainer = context.apiSuccess(MODULE, '首次关联真实已确认订舱柜', linkResponse, '', OPTIONS) + const linkedContainer = context.apiSuccess(MODULE, '首次关联真实已确认订舱柜', linkResponse, + responseEvidence(linkResponse), OPTIONS) + if (!linkedContainer) return const afterLinkPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`) const afterLinkPlan = context.apiSuccess(MODULE, '关联后回查原装柜计划与明细', afterLinkPlanResponse, '', OPTIONS) const afterLinkItems = JSON.stringify(afterLinkPlan?.items?.map((item) => ({ id: id(item.id), inboundId: id(item.inboundId), packageCount: Number(item.packageCount) })) || []) diff --git a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs index 68b35a4da..5570e4d66 100644 --- a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs @@ -149,6 +149,18 @@ test('container loading arranges a simulation before linking a confirmed real bo const draft = value.slice(value.indexOf('const bookingDraft = {'), value.indexOf('context.assert(MODULE, \'订舱渠道与仓库快照完整\'')) assert.doesNotMatch(draft, /billOfLadingNo|vesselName|voyageNo|estimatedSailingAt|estimatedArrivalAt/) assert.match(value, /containerAllocations\.length === 0/) + assert.match(value, /function responseEvidence\(response\)[\s\S]*HTTP=\$\{response\?\.http \?\? 'missing'\}[\s\S]*code=\$\{codeOf\(response\)\}[\s\S]*requestId=\$\{response\?\.requestId \|\| 'missing'\}[\s\S]*traceId=\$\{response\?\.traceId \|\| 'missing'\}/) + assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜首次关联真实订舱', emptyLink,\s+responseEvidence\(emptyLink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyUnlink = await request/) + assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜允许解除关联', emptyUnlink,\s+responseEvidence\(emptyUnlink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyRelink = await request/) + assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜解绑后允许重新关联', emptyRelink,\s+responseEvidence\(emptyRelink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyFinalUnlink = await request/) + assert.match(value, /const emptyReleased = context\.apiSuccess\(MODULE, '空模拟柜最终解绑释放真实订舱容量', emptyFinalUnlink,\s+responseEvidence\(emptyFinalUnlink\), OPTIONS\)\s+if \(!emptyReleased\) return\s+const beforeLinkItems/) + assertOrder(value, [ + "const linkedContainer = context.apiSuccess(MODULE, '首次关联真实已确认订舱柜', linkResponse,", + 'if (!linkedContainer) return', + "const afterLinkPlanResponse = await context.request('GET'", + "const duplicateSimulationResponse = await request(context, 'POST', CONTAINERS", + ]) + assert.equal(value.match(/responseEvidence\((?:emptyLink|emptyUnlink|emptyRelink|emptyFinalUnlink|linkResponse)\)/g)?.length, 5) assert.match(value, /关联前后内部柜次、计划和排货明细身份稳定/) assert.match(value, /bookingId=\$\{encodeURIComponent\(containerId\)\}&warehouseId=/) assert.match(value, /tasks\?loadingPlanId=\$\{encodeURIComponent\(planId\)\}&warehouseId=/)