import test from 'node:test' import assert from 'node:assert/strict' import fs from 'node:fs' import http from 'node:http' import path from 'node:path' import { fileURLToPath } from 'node:url' import { AcceptanceRun, normalizeModuleOrder } from './admin-test-env-acceptance.mjs' const here = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(here, 'admin-test-env-acceptance.mjs'), 'utf8') test('默认全量按新财务链执行直接收付款隔离且不包含旧 finance', () => { const match = source.match(/const CONFIGURED_MODULES = \[(.*?)\]/s) assert.ok(match) const modules = [...match[1].matchAll(/'([^']+)'/g)].map((item) => item[1]) const financeStart = modules.indexOf('finance-full-fixtures') assert.deepEqual(modules.slice(financeStart, financeStart + 5), [ 'finance-full-fixtures', 'finance-reconciliation-full', 'finance-settlement-full', 'finance-direct-paid-isolation', 'finance-downloads', ]) assert.equal(modules.includes('finance'), false) assert.match(source, /fullFinanceChain/) const normalized = normalizeModuleOrder(modules) const normalizedFinanceStart = normalized.indexOf('finance-full-fixtures') assert.deepEqual(normalized.slice(normalizedFinanceStart, normalizedFinanceStart + 5), [ 'finance-full-fixtures', 'finance-reconciliation-full', 'finance-settlement-full', 'finance-direct-paid-isolation', 'finance-downloads', ]) }) test('binary GET retries transient transport failures without retrying writes', () => { assert.match(source, /async requestBinary\([\s\S]*?const maxAttempts = \['GET', 'HEAD'\]/) assert.match(source, /async requestBinary\([\s\S]*?attempt < maxAttempts/) }) test('multipart request preserves FormData boundary and unified response evidence', () => { assert.match(source, /async requestMultipart\(/) assert.match(source, /form\.append\('file'/) assert.match(source, /body instanceof FormData \? body : JSON\.stringify\(body\)/) assert.doesNotMatch(source, /requestMultipart[\s\S]{0,500}Content-Type.*multipart/i) }) test('multipart helper sends the File upload contract and parses unified evidence', async (t) => { let received = null const server = http.createServer((request, response) => { const chunks = [] request.on('data', (chunk) => chunks.push(chunk)) request.on('end', () => { received = { headers: request.headers, body: Buffer.concat(chunks).toString('latin1') } response.writeHead(200, { 'Content-Type': 'application/json', 'X-Request-Id': 'request-1', 'X-Trace-Id': 'trace-1' }) response.end(JSON.stringify({ code: '200', data: { fileId: '9' } })) }) }) await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)) t.after(() => server.close()) const address = server.address() const run = new AcceptanceRun({ gateway: `http://127.0.0.1:${address.port}` }) run.token = 'contract-token' const result = await run.requestMultipart('POST', '/api/platform/finance/v1/vouchers?customerId=7', { name: 'voucher.txt', type: 'text/plain', content: new TextEncoder().encode('voucher fixture'), }) assert.equal(result.http, 200) assert.equal(result.body.data.fileId, '9') assert.equal(result.requestId, 'request-1') assert.equal(result.traceId, 'trace-1') assert.equal(received.headers.authorization, 'Bearer contract-token') assert.match(received.headers['content-type'], /^multipart\/form-data; boundary=/) assert.match(received.body, /name="file"; filename="voucher\.txt"/) assert.match(received.body, /voucher fixture/) }) test('module failures, coverage gaps and deployment blockers remain report surfaces', () => { for (const field of ['this.modules.push', 'coverageGaps', 'deploymentBlockers']) assert.match(source, new RegExp(field.replace('.', '\\.'), 's')) assert.match(source, /async executeModule\(name, handler\)/) assert.match(source, /const extension = await import\(new URL\(`\.\/admin-test-env-modules\/\$\{module\}/) })