文件
hyb-oa/scripts/qa/tests/workflow-payment-profile.test.mjs
T
wangsli 1f8d5b658a 完善借款、编号、付款与预算并发及验收(09-06-release-gate-integrity)
汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。
统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。
纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。

关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。
预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。
完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
2026-09-19 13:11:04 +08:00

48 行
2.7 KiB
JavaScript

import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import test from 'node:test';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
const source = readFileSync(path.join(root, 'server/scripts/regression-workflow-actions.sh'), 'utf8');
function checkResponse(context, code, details, candidate = source) {
const directory = mkdtempSync(path.join(os.tmpdir(), 'hyb-payment-profile-'));
context.after(() => rmSync(directory, { recursive: true, force: true }));
writeFileSync(path.join(directory, 'pay-ok-pay.json'), JSON.stringify({ error: { code: 'VALID_001', details } }));
// Execute the candidate's real shell assertions. No app, database, or HTTP tools are started.
const helpers = ['assert_status', 'assert_error_code', 'assert_error_detail'].map(name => {
const start = candidate.indexOf(name + '() {');
assert.ok(start >= 0);
const end = candidate.indexOf('\n}\n', start);
assert.ok(end > start);
return candidate.slice(start, end + 3);
}).join('\n');
const start = candidate.indexOf('if [[', candidate.indexOf('\npay_ok_status='));
const end = candidate.indexOf(' echo "[19/23] batch-required profile:', start);
assert.ok(start >= 0 && end > start);
const script = 'set -euo pipefail\n' + helpers + '\n' + candidate.slice(start, end) + '\nfi\n';
return spawnSync('bash', ['-c', script], {
env: { PATH: process.env.PATH, TMP_DIR: directory, PAYMENT_BATCH_ENABLED: 'true', pay_ok_status: String(code) },
encoding: 'utf8', timeout: 10000,
});
}
test('configured batch mode accepts only the exact batch-required refusal', context => {
const valid = { payment: 'payment_batch_v1_required', reasonCode: 'reimbursement.payment_payment_batch_v1_required' };
assert.equal(checkResponse(context, 409, valid).status, 0);
for (const code of [200, 400, 403, 500]) assert.notEqual(checkResponse(context, code, valid).status, 0);
assert.notEqual(checkResponse(context, 409, { payment: 'some_other_reason' }).status, 0);
});
test('choosing the branch from the observed response is detected as a false-green mutation', context => {
const before = 'if [[ "${PAYMENT_BATCH_ENABLED:-false}" == "true" ]]; then';
assert.ok(source.includes(before));
const mutant = source.replace(before, 'if [[ "$pay_ok_status" == "409" ]]; then');
const verify = candidate => assert.notEqual(checkResponse(context, 200, {}, candidate).status, 0);
verify(source);
assert.throws(() => verify(mutant), assert.AssertionError);
});