文件
hyb-oa/scripts/qa/tests/full-local-coverage.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

69 行
5.3 KiB
JavaScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { coveragePlan, verifyLocalCoverage, verifyPostDeployCoverage } from "../full-local-coverage.mjs";
const candidate = { commit: "a".repeat(40), digest: "b".repeat(64) };
function report(rows, executed = false) {
return { errors: [], suites: rows.map(row => ({ file: row.file, specs: [{ ...row, tests: [{ projectName: "", repeatEachIndex: 0, ...(executed ? { expectedStatus: "passed", status: "expected", results: [{ status: "passed", retry: 0 }] } : {}) }] }] })) };
}
function fixture(context) {
const root = mkdtempSync(path.join(os.tmpdir(), "hyb-coverage-"));
context.after(() => rmSync(root, { recursive: true, force: true }));
const rows = ["local", "live", "frozen", "protection"].map(name => ({ file: `client/tests/e2e/${name}.spec.ts`, id: name, title: name, projectName: "", repeatEachIndex: 0 }));
for (const row of rows) { mkdirSync(path.dirname(path.join(root, row.file)), { recursive: true }); writeFileSync(path.join(root, row.file), row.title); }
const contract = { schemaVersion: 1, approvalReference: "synthetic", exceptions: rows.slice(1, 3).map(row => ({ ...row, kind: row.id === "live" ? "post-deploy" : "frozen", reason: "synthetic", entry: "synthetic", responsibilityRole: "synthetic", namedOwner: null, requiredEvidence: "synthetic", sourceSha256: createHash("sha256").update(row.title).digest("hex"), replacementFile: rows[3].file, replacementTitle: rows[3].title })) };
const discovery = report(rows);
const plan = () => coveragePlan(root, discovery, contract, candidate);
return { root, rows, contract, discovery, plan };
}
test("全发现分层,本地通过仍保留公网必跑且不能获得交付资格", context => {
const f = fixture(context), p = f.plan();
assert.equal(p.status, "PASS"); assert.equal(p.totalCases, 4); assert.equal(p.localCases.length, 2);
const r = verifyLocalCoverage(p, report(p.localCases, true), candidate);
assert.equal(r.status, "PASS"); assert.equal(r.deliveryStatus, "INCOMPLETE"); assert.equal(r.normalReleaseEligible, false);
assert.deepEqual(r.obligations.map(row => row.status), ["NOT_RUN_LOCAL", "FROZEN_PROTECTION_PASS"]);
});
for (const mutation of ["missing-file", "new-file", "new-live-case", "identity-drift", "duplicate", "source-drift", "no-protection", "unknown-exception", "missing-reason"]) test(`发现/归属反例:${mutation}`, context => {
const f = fixture(context);
if (mutation === "missing-file") f.discovery.suites.pop();
if (mutation === "new-file") writeFileSync(path.join(f.root, "client/tests/e2e/new.spec.ts"), "new");
if (mutation === "new-live-case") f.discovery.suites[1].specs.push({ ...f.discovery.suites[1].specs[0], id: "new-live", title: "new-live" });
if (mutation === "identity-drift") f.discovery.suites[1].specs[0].id = "drift";
if (mutation === "duplicate") f.discovery.suites.push(f.discovery.suites[0]);
if (mutation === "source-drift") writeFileSync(path.join(f.root, f.rows[1].file), "changed");
if (mutation === "no-protection") f.contract.exceptions[1].replacementTitle = "missing";
if (mutation === "unknown-exception") f.contract.exceptions[1].kind = "ignore";
if (mutation === "missing-reason") delete f.contract.exceptions[0].reason;
assert.equal(f.plan().status, "FAIL");
});
for (const mutation of ["missing", "unexpected", "duplicate", "skipped", "failed", "timedOut", "interrupted", "retry", "expected-failure", "fake-pass", "candidate", "errors", "title-drift"]) test(`本地结果反例:${mutation}`, context => {
const f = fixture(context), p = f.plan(), r = report(p.localCases, true);
let current = candidate;
const row = r.suites[0].specs[0].tests[0];
if (mutation === "missing") r.suites.pop();
if (mutation === "unexpected") r.suites.push(report([f.rows[1]], true).suites[0]);
if (mutation === "duplicate") r.suites.push(r.suites[0]);
if (["skipped", "failed", "timedOut", "interrupted"].includes(mutation)) row.results[0].status = mutation;
if (mutation === "retry") row.results.push({ status: "passed", retry: 1 });
if (mutation === "expected-failure") row.expectedStatus = "failed";
if (mutation === "fake-pass") { r.passed = true; delete row.results; }
if (mutation === "candidate") current = { ...candidate, digest: "c".repeat(64) };
if (mutation === "errors") r.errors.push({ message: "synthetic" });
if (mutation === "title-drift") r.suites[0].specs[0].title = "changed";
assert.equal(verifyLocalCoverage(p, r, current).status, "FAIL");
});
test("公网只接受同候选 live 逐项结果,不接受本地或布尔通过", context => {
const f = fixture(context), p = f.plan();
const good = { profile: "post-deploy-live", mode: "live", candidate, deployedCandidate: candidate, report: report([f.rows[1]], true) };
assert.equal(verifyPostDeployCoverage(p, good).status, "PASS");
for (const bad of [{ passed: true }, { ...good, profile: "full-local" }, { ...good, mode: "local" }, { ...good, deployedCandidate: { ...candidate, commit: "c".repeat(40) } }, { ...good, candidate: { ...candidate, digest: "d".repeat(64) } }, { ...good, report: report(p.localCases, true) }]) assert.equal(verifyPostDeployCoverage(p, bad).status, "FAIL");
});