mirror of
https://github.com/openclaw/openclaw.git
synced 2026-11-01 04:58:23 +00:00
fix(qa): accept --evidence on the source QA fallback command The source QA fallback command didn't register the --evidence option, so a gap report run from source failed with an unknown-option error and wrote nothing. The option is now registered and handed to the existing report builder. Evidence: built CLI on Node 24.22.1, running the public source fallback (12 calls). Main rejected --evidence and created no output (twice); with this change it wrote the 2036-row gap report with matching output hashes and unchanged input hashes (twice). Tools and unknown-option controls behave the same on both refs. Details: https://github.com/openclaw/openclaw/pull/186747#issuecomment-6472915979. Thanks @Alix-007. Co-authored-by: Ayaan Zaidi <hi@obviy.us>
89 lines
3.3 KiB
TypeScript
89 lines
3.3 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { afterEach, expect, it } from "vitest";
|
|
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
|
|
|
|
const repoRoot = path.resolve(__dirname, "../..");
|
|
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
|
// Release reports must still work when the execution runtime is unavailable.
|
|
const withoutExecutionRuntime = `data:text/javascript,${encodeURIComponent(`
|
|
import { registerHooks } from "node:module";
|
|
registerHooks({
|
|
resolve(specifier, context, nextResolve) {
|
|
if (specifier.endsWith("/qa-lab/src/cli.runtime.ts")) {
|
|
throw new Error("QA execution runtime is unavailable");
|
|
}
|
|
return nextResolve(specifier, context);
|
|
},
|
|
});
|
|
`)}`;
|
|
|
|
function runSourceScript(scriptPath: string, ...args: string[]) {
|
|
return spawnSync(
|
|
process.execPath,
|
|
["--import", withoutExecutionRuntime, "--import", "tsx", scriptPath, ...args],
|
|
{ cwd: repoRoot, encoding: "utf8" },
|
|
);
|
|
}
|
|
|
|
it.each([
|
|
["coverage", "--wat", "Unknown qa coverage option: --wat"],
|
|
["parity", "--wat", "Unknown qa parity-report option: --wat"],
|
|
["coverage", "--evidence", "--evidence requires a value"],
|
|
])("reports invalid QA %s %s options without a Node stack trace", (script, flag, error) => {
|
|
const result = runSourceScript(`scripts/qa-${script}-report.ts`, flag);
|
|
expect(result).toMatchObject({ status: 1, stdout: "" });
|
|
expect(result.stderr.trim()).toBe(error);
|
|
expect(result.stderr).not.toMatch(/Node\.js|\n {4}at /u);
|
|
});
|
|
|
|
it("prints tool coverage without loading the QA execution runtime", () => {
|
|
const result = runSourceScript("scripts/qa-coverage-report.ts", "--tools", "--json");
|
|
expect(result.status, result.stderr).toBe(0);
|
|
const report: { totalTools: number } = JSON.parse(result.stdout);
|
|
expect(report).toMatchObject({ evaluated: false, pass: true });
|
|
expect(report.totalTools).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("writes failed parity artifacts without the execution runtime", async () => {
|
|
const fixtureRoot = tempDirs.make("qa-report-cli-");
|
|
for (const [label, status] of [
|
|
["candidate", "pass"],
|
|
["baseline", "fail"],
|
|
]) {
|
|
await fs.writeFile(
|
|
path.join(fixtureRoot, `${label}.json`),
|
|
JSON.stringify({
|
|
run: { status: "completed" },
|
|
scenarios: [{ name: "report-fixture", status, steps: [] }],
|
|
}),
|
|
);
|
|
}
|
|
const result = runSourceScript(
|
|
"scripts/qa-parity-report.ts",
|
|
...Object.entries({
|
|
"repo-root": fixtureRoot,
|
|
"candidate-summary": "candidate.json",
|
|
"baseline-summary": "baseline.json",
|
|
"candidate-label": "candidate",
|
|
"baseline-label": "baseline",
|
|
"output-dir": "report",
|
|
}).flatMap(([flag, value]) => [`--${flag}`, value]),
|
|
);
|
|
|
|
expect(result).toMatchObject({ stderr: "", status: 1 });
|
|
expect(result.stdout).toContain("QA parity verdict: fail");
|
|
const artifact = (name: string) =>
|
|
fs.readFile(path.join(fixtureRoot, `report/qa-agentic-parity-${name}`), "utf8");
|
|
const summary: { pass: boolean; scenarioComparisons: unknown[] } = JSON.parse(
|
|
await artifact("summary.json"),
|
|
);
|
|
expect(summary.pass).toBe(false);
|
|
expect(summary.scenarioComparisons).toContainEqual({
|
|
name: "report-fixture",
|
|
candidateStatus: "pass",
|
|
baselineStatus: "fail",
|
|
});
|
|
expect(await artifact("report.md")).toContain("report-fixture");
|
|
});
|