Files
openclaw/extensions/qa-matrix/src/cli.test.ts
2026-04-27 05:43:14 +01:00

102 lines
3.3 KiB
TypeScript

import { Command } from "commander";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const { runQaMatrixCommand } = vi.hoisted(() => ({
runQaMatrixCommand: vi.fn(),
}));
vi.mock("./cli.runtime.js", () => ({
runQaMatrixCommand,
}));
import { matrixQaCliRegistration } from "./cli.js";
function mockProcessWrite(
_chunk: string | Uint8Array,
encodingOrCallback?: BufferEncoding | ((err?: Error | null) => void),
callback?: (err?: Error | null) => void,
) {
if (typeof encodingOrCallback === "function") {
encodingOrCallback();
} else {
callback?.();
}
return true;
}
describe("matrix qa cli registration", () => {
const originalDisableForceExit = process.env.OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT;
let exitSpy: ReturnType<typeof vi.spyOn>;
let stderrSpy: ReturnType<typeof vi.spyOn>;
let stdoutSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
runQaMatrixCommand.mockReset();
exitSpy = vi.spyOn(process, "exit").mockImplementation((code?: string | number | null) => {
throw new Error(`process.exit(${String(code)})`);
});
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(mockProcessWrite);
stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(mockProcessWrite);
});
afterEach(() => {
if (originalDisableForceExit === undefined) {
delete process.env.OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT;
} else {
process.env.OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT = originalDisableForceExit;
}
exitSpy.mockRestore();
stderrSpy.mockRestore();
stdoutSpy.mockRestore();
});
it("keeps disposable Matrix lane flags focused", () => {
const qa = new Command();
matrixQaCliRegistration.register(qa);
const matrix = qa.commands.find((command) => command.name() === "matrix");
const optionNames = matrix?.options.map((option) => option.long) ?? [];
expect(optionNames).toEqual(
expect.arrayContaining([
"--repo-root",
"--output-dir",
"--provider-mode",
"--model",
"--alt-model",
"--scenario",
"--fast",
"--profile",
"--fail-fast",
"--sut-account",
]),
);
expect(optionNames).not.toContain("--credential-source");
expect(optionNames).not.toContain("--credential-role");
});
it("exits with failure after Matrix artifacts are written for a failed run", async () => {
const qa = new Command();
matrixQaCliRegistration.register(qa);
runQaMatrixCommand.mockRejectedValue(new Error("Matrix QA failed.\nreport: /tmp/report.md"));
await expect(qa.parseAsync(["node", "openclaw", "matrix"])).rejects.toThrow("process.exit(1)");
expect(runQaMatrixCommand).toHaveBeenCalledOnce();
expect(stderrSpy).toHaveBeenCalledWith("Matrix QA failed.\nreport: /tmp/report.md\n");
expect(exitSpy).toHaveBeenCalledWith(1);
});
it("can disable the forced exit for direct test harnesses", async () => {
process.env.OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT = "1";
const qa = new Command();
matrixQaCliRegistration.register(qa);
runQaMatrixCommand.mockRejectedValue(new Error("scenario failed"));
await expect(qa.parseAsync(["node", "openclaw", "matrix"])).rejects.toThrow("scenario failed");
expect(exitSpy).not.toHaveBeenCalled();
});
});