import assert from "node:assert/strict"; import { mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { test } from "node:test"; import { componentSuites, runComponentTests, selectSuites } from "../scripts/run-component-tests.mjs"; test("component aliases select the existing contract and reject unknown input", () => { assert.deepEqual(selectSuites([]), Object.keys(componentSuites)); assert.deepEqual(selectSuites(["page-layout", "page-layout"]), ["page-layout"]); assert.deepEqual(componentSuites["data-grid-actions"], ["data-grid-actions", "data-grid-sizing"]); assert.throws(() => selectSuites(["../../unowned"]), /Unknown component suite/); }); test("every configured component test remains covered by the batch and standalone aliases", () => { const config = JSON.parse(readFileSync(new URL("../tsconfig.component-tests.json", import.meta.url), "utf8")); const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); const configured = config.include.filter((file) => file.startsWith("tests/")).map((file) => file.replace(/^tests\//, "").replace(/\.test\.tsx?$/, "")).sort(); assert.deepEqual(Object.values(componentSuites).flat().sort(), configured); for (const name of Object.keys(componentSuites)) { assert.equal(packageJson.scripts[`test:${name}`], `node scripts/run-component-tests.mjs ${name}`); } assert.equal(packageJson.scripts["test:components"], "node scripts/run-component-tests.mjs"); }); test("one compile serves a batch and preserves structural follow-ups", async () => { const root = mkdtempSync(join(tmpdir(), "govoplan-component-runner-")); const commands = []; try { const result = await runComponentTests({ webuiRoot: root, compiler: "fixture-tsc", names: ["data-grid-actions", "dialog-focus"], run: async (argv) => commands.push(argv) }); assert.equal(result.compiled, 1); assert.equal(commands.filter((argv) => argv[1] === "fixture-tsc").length, 1); assert.equal(commands.length, 5); assert(commands.at(-1)[1].endsWith("test-dialog-focus-structure.mjs")); assert.deepEqual(readdirSync(root), []); } finally { rmSync(root, { recursive: true, force: true }); } }); test("overlapping runs have separate outputs and failures clean only owned output", async () => { const root = mkdtempSync(join(tmpdir(), "govoplan-component-runner-")); const outputs = []; let unblock; const bothStarted = new Promise((resolve) => { unblock = resolve; }); const run = async (argv) => { if (argv[1] !== "fixture-tsc") return; outputs.push(argv.at(-1)); if (outputs.length === 2) unblock(); await bothStarted; throw new Error("fixture compilation failed"); }; try { const results = await Promise.allSettled([1, 2].map(() => runComponentTests({ webuiRoot: root, compiler: "fixture-tsc", names: ["page-layout"], run }))); assert(results.every((result) => result.status === "rejected")); assert.equal(new Set(outputs).size, 2); assert.deepEqual(readdirSync(root), []); } finally { rmSync(root, { recursive: true, force: true }); } });