import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { AcceptanceRun, parseArguments, validateExecutionOptions } from './admin-test-env-acceptance.mjs' const source = readFileSync(resolve('scripts/admin-test-env-acceptance.mjs'), 'utf8') test('phase-four HTTP acceptance modules are registered in the Admin acceptance entry', () => { for (const module of [ 'phase4-overseas-warehouse', 'phase4-overseas-pda', 'phase4-overseas-pda-operations', 'phase4-overseas-inbound-operations', 'phase4-overseas-client-services', 'phase4-overseas-dispatch', 'phase4-cross-region-events', 'phase4-overseas-business', 'phase4-overseas-master-data', 'phase4-carrier-nodes', ]) { assert.match(source, new RegExp(`CONFIGURED_MODULES\\s*=\\s*\\[[^\\]]*'${module}'`, 's')) } }) test('overseas inbound commands, client services and dispatch follow completed PDA receiving', () => { for (const consumer of ['phase4-overseas-inbound-operations', 'phase4-overseas-client-services', 'phase4-overseas-dispatch']) { const modules = parseArguments(['--modules', consumer]).modules for (const prerequisite of ['merchant-qualification-fixture', 'phase3-loading', 'phase3-loading-finalize', 'phase4-overseas-pda', 'phase4-overseas-pda-operations']) { assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf(consumer)) } } }) test('entry accepts a separate overseas Gateway without exposing token state', () => { const options = parseArguments([ '--gateway', 'http://localhost:9000/', '--overseas-gateway', 'http://localhost:9300/', '--modules', 'phase4-overseas-warehouse', ]) assert.equal(options.gateway, 'http://localhost:9000') assert.equal(options.overseasGateway, 'http://localhost:9300') assert.match(source, /this\.overseasToken = login\.overseasAccessToken \|\| ''/) assert.match(source, /this\.refreshToken = login\.refreshToken \|\| ''/) assert.match(source, /this\.overseasExpiresAt = Number\(login\.overseasExpiresIn\)/) assert.match(source, /async refreshSession\(reason\)/) assert.match(source, /refreshToken: this\.refreshToken/) assert.match(source, /const replacement = \{[\s\S]*token: next\.accessToken[\s\S]*refreshToken: next\.refreshToken[\s\S]*overseasToken: next\.overseasAccessToken/) assert.match(source, /module === 'system' && laterOverseasModule/) assert.match(source, /system后新admin海外Token只读探针可用/) assert.match(source, /module\.startsWith\('phase4-overseas-'\)[\s\S]*Date\.now\(\) \+ 120_000 >= this\.overseasExpiresAt/) assert.match(source, /海外模块 \$\{module\} 执行前Token临近到期/) assert.match(source, /async requestOverseas\(/) assert.match(source, /async requestOverseasBinary\(/) assert.match(source, /async requestOverseasMultipart\(/) assert.match(source, /forbiddenValues = \[this\.options\.password, this\.options\.merchantPassword,[\s\S]*this\.token, this\.refreshToken, this\.overseasToken\]/) }) test('dual-token refresh replaces the whole session only after a complete response', async () => { const run = new AcceptanceRun({ gateway: 'http://localhost:9000', overseasGateway: 'http://localhost:9300', username: 'contract-user', password: 'contract-password', modules: [], output: '' }) Object.assign(run, { token: 'old-access', refreshToken: 'old-refresh', overseasToken: 'old-overseas', overseasExpiresAt: 1 }) run.request = async (method, path, body, token) => { assert.equal(method, 'POST'); assert.equal(path, '/api/auth/refresh') assert.deepEqual(body, { refreshToken: 'old-refresh' }); assert.equal(token, '') return { method, path, http: 200, body: { code: '200', data: { accessToken: 'new-access', refreshToken: 'new-refresh', overseasAccessToken: 'new-overseas', overseasExpiresIn: 900, } }, requestId: 'refresh-request', traceId: 'refresh-trace' } } assert.equal(await run.refreshSession('contract'), true) assert.equal(run.token, 'new-access') assert.equal(run.refreshToken, 'new-refresh') assert.equal(run.overseasToken, 'new-overseas') assert.ok(run.overseasExpiresAt > Date.now()) const frozen = { token: run.token, refreshToken: run.refreshToken, overseasToken: run.overseasToken, overseasExpiresAt: run.overseasExpiresAt } run.request = async (method, path) => ({ method, path, http: 200, body: { code: '200', data: { accessToken: 'partial-only' } }, requestId: 'partial-request', traceId: 'partial-trace' }) assert.equal(await run.refreshSession('incomplete-contract'), false) assert.deepEqual({ token: run.token, refreshToken: run.refreshToken, overseasToken: run.overseasToken, overseasExpiresAt: run.overseasExpiresAt }, frozen) }) test('entry has no built-in environment address or password and requires explicit execution options', () => { assert.doesNotMatch(source, /8\.163\.|ChangeMe123|DEFAULT_PASSWORD|DEFAULT_GATEWAY/) assert.throws(() => validateExecutionOptions(parseArguments(['--modules', 'phase4-overseas-pda'])), /缺少必填执行参数/) const options = parseArguments([ '--gateway', 'http://localhost:9000', '--overseas-gateway', 'http://localhost:9300', '--username', 'contract-user', '--password', 'contract-password', '--modules', 'phase4-overseas-pda', ]) assert.equal(validateExecutionOptions(options), options) }) test('core coverage gaps fail closed while device and external-provider gaps remain report-only', () => { const run = new AcceptanceRun({ gateway: 'http://localhost:9000', overseasGateway: 'http://localhost:9300', username: 'contract-user', password: 'contract-password', modules: [], output: '' }) run.addCoverageGap('phase4', 'core', 'fixture', 'missing fixture', 'fixture') assert.equal(run.steps.at(-1)?.passed, false) assert.equal(run.steps.at(-1)?.deploymentBlocker, true) const stepCount = run.steps.length run.addCoverageGap('phase3', 'device', 'Android', 'manual device validation', 'device') run.addCoverageGap('phase3', 'provider', 'captcha', 'external captcha', 'external-third-party') assert.equal(run.steps.length, stepCount) }) test('PDA entry expands the real phase-three producer chain and builds an FBA/OVERSEAS/second-container matrix', () => { const modules = parseArguments(['--modules', 'phase4-overseas-pda']).modules for (const prerequisite of ['merchant-qualification-fixture', 'phase3-loading', 'phase3-pda-convergence', 'phase3-evidence-gate', 'phase3-loading-finalize']) { assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf('phase4-overseas-pda')) } assert.match(source, /async ensurePhase4PdaProducerMatrix\(\)/) assert.match(source, /runPhase4ProducerVariant\('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP', true\)/) assert.match(source, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS', 'STANDARD', true\)/) assert.match(source, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', false\)/) assert.match(source, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/) assert.match(source, /runUntilPickupReady\(this\)/) assert.match(source, /carrierScheduleQueryId/) assert.match(source, /readyForPhase4Pda === true/) assert.equal(modules.indexOf('phase4-overseas-pda-operations'), modules.indexOf('phase4-overseas-pda') + 1) })