import assert from 'node:assert/strict' import fs from 'node:fs' import path from 'node:path' import test from 'node:test' import { fileURLToPath } from 'node:url' import { normalizeModuleOrder } from '../admin-test-env-acceptance.mjs' import { run } from './phase4-overseas-pda-operations.mjs' const here = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(here, 'phase4-overseas-pda-operations.mjs'), 'utf8') const receivingSource = fs.readFileSync(path.join(here, 'phase4-overseas-pda.mjs'), 'utf8') const entrySource = fs.readFileSync(path.join(here, '..', 'admin-test-env-acceptance.mjs'), 'utf8') test('PDA operations run immediately after receiving and all later consumers depend on cleanup completion', () => { const modules = normalizeModuleOrder(['phase4-overseas-client-services']) const receiving = modules.indexOf('phase4-overseas-pda') const operations = modules.indexOf('phase4-overseas-pda-operations') const consumer = modules.indexOf('phase4-overseas-client-services') assert.ok(receiving >= 0 && operations === receiving + 1 && consumer > operations) assert.match(entrySource, /'phase4-overseas-pda-operations', \['phase4-overseas-pda'\]/) for (const module of ['phase4-overseas-inbound-operations', 'phase4-overseas-client-services', 'phase4-overseas-dispatch', 'phase4-cross-region-events', 'phase4-carrier-nodes']) { assert.match(entrySource, new RegExp(`'${module}', \\[[^\\]]*'phase4-overseas-pda-operations'`)) } }) test('receiving hands off only transient credentials and completed warehouse facts', () => { assert.match(receivingSource, /context\.context\.phase4OverseasPdaOperations = \{/) assert.match(receivingSource, /completedFixtures: \[\]/) assert.match(receivingSource, /if \(!handoffReady\) \{[\s\S]*await cleanup\(\)/) assert.doesNotMatch(receivingSource, /createdResources\.phase4OverseasPdaOperations/) assert.doesNotMatch(receivingSource, /primary: primary \? \{[^}]*password/) assert.doesNotMatch(entrySource.match(/const reportSurface = JSON\.stringify\(\{([\s\S]*?)\n \}\)/)?.[1] || '', /context/) }) test('P2 to P5 cover all frozen endpoints, replays and conflict boundaries without outbound domains', () => { for (const endpoint of [ '/api/pda/v1/last-leg/stocktakes', '/api/pda/v1/last-leg/inventory-moves', '/api/pda/v1/last-leg/pallet-operations/pallets/resolve', '/swap', '/disassemble', '/assemble', '/unbind', '/api/pda/v1/last-leg/relabel-tasks', '/candidates', '/claim', '/units', '/skip', '/exceptions', '/photos/files', '/complete', '/review', ]) assert.ok(source.includes(endpoint), endpoint) for (const marker of ['按原数计数', '同键重放', '同键异载荷A0409', '旧版本A0409', 'SUBMITTED', '移回原库位', 'WAIT_REVIEW', 'REWORK', 'APPROVE', 'COMPLETED']) { assert.ok(source.includes(marker), marker) } for (const forbidden of ['/outbound', '/returns/outbound', '/dispatch', '/delivery', '/internal/']) { assert.equal(source.includes(forbidden), false, forbidden) } assert.doesNotMatch(source, /fetch\(|https?:\/\//) assert.match(source, /requestId=/) assert.match(source, /traceId=/) }) test('fixture failure still disables both picker accounts and removes all transient tokens', async () => { const cleanups = [] const gaps = [] const steps = [] const handoff = { marker: 'PDAOPS-CONTRACT', primary: { membershipId: '1', username: 'primary', token: 'primary-secret-token' }, secondary: { membershipId: '2', username: 'secondary', token: 'secondary-secret-token' }, completedFixtures: [], async cleanup() { cleanups.push('secondary', 'primary') }, } const context = { marker: 'PDAOPS-CONTRACT', context: { phase4OverseasPdaOperations: handoff }, createdResources: {}, addCoverageGap(...args) { gaps.push(args) }, assert(module, name, response, passed, evidence, options) { steps.push({ module, name, passed, evidence, options }) }, } await run(context) assert.deepEqual(cleanups, ['secondary', 'primary']) assert.equal(handoff.primary.token, undefined) assert.equal(handoff.secondary.token, undefined) assert.equal(context.context.phase4OverseasPdaOperations, undefined) assert.ok(gaps.some((gap) => gap[2] === 'P2-P5本轮PDA收货交接')) assert.ok(steps.some((step) => !step.passed && step.options?.deploymentBlocker)) assert.equal(JSON.stringify(context).includes('secret-token'), false) })