import { describe, expect, it } from "vitest"; import { selfCheckMain, type SelfCheckMainDeps } from "../../tools/selfCheckMain"; import type { SelfCheckResult, SelfCheckScript } from "../../tools/selfCheck"; function deps(over: Partial = {}) { const out: string[] = []; const err: string[] = []; const files = new Map(); const d: SelfCheckMainDeps = { cwd: "/proj", out: (s) => out.push(s), err: (s) => err.push(s), loadScripts: (): SelfCheckScript[] => [ { name: "click.pass", text: "# expect: pass\n" }, { name: "click.fail-nothing", text: "# expect: fail not-found click\n" }, ], chromePath: () => "/chrome", runCheck: async () => ({ exitCode: 0, report: "SELF-CHECK PASSED", scripts: [] }) as unknown as SelfCheckResult, makeDir: () => {}, writeFile: (p, c) => void files.set(p, c), resolve: (p) => `/abs/${p}`, ...over, }; return { d, out, err, files }; } describe("selfCheckMain", () => { it("--help prints the usage and exits 0", async () => { const x = deps(); expect(await selfCheckMain(["--help"], x.d)).toBe(0); expect(x.out.join("\n")).toContain("--repeat"); }); it("a bad option prints the problem on stderr and exits 2", async () => { const x = deps(); expect(await selfCheckMain(["--turbo"], x.d)).toBe(2); expect(x.err.join("\n")).toContain('unknown option "--turbo"'); expect(x.out).toEqual([]); }); it("--list names every script and what it must do, and runs nothing", async () => { let ran = false; const x = deps({ runCheck: async () => { ran = true; return { exitCode: 0, report: "", scripts: [] } as unknown as SelfCheckResult; } }); expect(await selfCheckMain(["--list"], x.d)).toBe(0); expect(ran).toBe(false); const text = x.out.join("\n"); expect(text).toMatch(/click\.pass\s+pass/); expect(text).toMatch(/click\.fail-nothing\s+fail not-found click/); }); it("--list shows a script whose expectation line is wrong as a MISTAKE", async () => { const x = deps({ loadScripts: () => [{ name: "oops", text: "no expectation here\n" }] }); await selfCheckMain(["--list"], x.d); expect(x.out.join("\n")).toContain("MISTAKE"); }); it("a run passes its options on, writes report.txt and summary.json, prints the report and exits with the check's code", async () => { let seen: Record = {}; const x = deps({ runCheck: async (o) => { seen = o as unknown as Record; return { exitCode: 1, report: "SELF-CHECK FAILED", scripts: [{ name: "a" }] } as unknown as SelfCheckResult; }, }); expect(await selfCheckMain(["--repeat", "3", "--parallel", "2", "--sabotage", "verify", "--only", "click", "--out", "o"], x.d)).toBe(1); expect(seen).toMatchObject({ root: "/proj", chrome: "/chrome", repeat: 3, parallel: 2, sabotage: "verify", only: "click" }); expect(x.files.get("/abs/o/report.txt")).toBe("SELF-CHECK FAILED\n"); expect(JSON.parse(x.files.get("/abs/o/summary.json")!)).toMatchObject({ exitCode: 1, sabotage: "verify", scripts: [{ name: "a" }] }); expect(x.out.join("\n")).toContain("SELF-CHECK FAILED"); }); it("without --sabotage or --only they are left out and the summary says sabotage null", async () => { let seen: Record = {}; const x = deps({ runCheck: async (o) => { seen = o as unknown as Record; return { exitCode: 0, report: "ok", scripts: [] } as unknown as SelfCheckResult; } }); await selfCheckMain([], x.d); expect("sabotage" in seen).toBe(false); expect("only" in seen).toBe(false); expect(JSON.parse(x.files.get("/abs/results/selfcheck/summary.json")!).sabotage).toBeNull(); }); it("no pinned Chrome is a loud exit 3, not a skip", async () => { const x = deps({ chromePath: () => { throw new Error("no pinned Chrome here"); } }); expect(await selfCheckMain([], x.d)).toBe(3); expect(x.err.join("\n")).toContain("no pinned Chrome here"); }); });