- 427 orphaned dashboard test files ran in NO gate; 395 now gated via self-maintaining backfill lanes (glob minus curated minus skip-list), 31 pre-existing failures + build-output skip-listed with reasons - settings -t name-filter lanes replaced by one unfiltered lane (describe blocks can no longer fall through filters) - scripts/check-test-inventory.mjs: --capture/--diff superset harness + --dashboard-curated completeness guard - pr-checks.yml: engine-slow CI gate (non-empty assertion) + inventory guard job - docs/testing.md: guard, skip-list policy, harness usage
162 lines
6.1 KiB
JavaScript
162 lines
6.1 KiB
JavaScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import {
|
|
captureInventory,
|
|
diffInventories,
|
|
validateDashboardCurated,
|
|
} from "../check-test-inventory.mjs";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// capture (with an injected listFn so we never spawn real vitest)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function withSpec(spec, fn) {
|
|
const dir = mkdtempSync(join(tmpdir(), "inv-spec-"));
|
|
const specPath = join(dir, "spec.json");
|
|
writeFileSync(specPath, JSON.stringify(spec));
|
|
try {
|
|
return fn(specPath);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
test("capture: normalizes vitest list rows into package/project/file/testId records", () => {
|
|
const spec = {
|
|
packages: [{ name: "@pkg/a", dir: "packages/a", projects: ["proj-a"] }],
|
|
};
|
|
const repoRoot = "/repo";
|
|
const listFn = () => [
|
|
{ name: "does a thing", file: "/repo/packages/a/__tests__/x.test.ts", projectName: "proj-a" },
|
|
{ name: "does another", file: "/repo/packages/a/__tests__/y.test.ts", projectName: "proj-a" },
|
|
];
|
|
const inv = withSpec(spec, (specPath) =>
|
|
captureInventory({ specPathOverride: specPath, repoRoot, listFn }),
|
|
);
|
|
assert.equal(inv.records.length, 2);
|
|
assert.ok(inv.capturedAt);
|
|
assert.deepEqual(
|
|
inv.records.map((r) => r.file).sort(),
|
|
["packages/a/__tests__/x.test.ts", "packages/a/__tests__/y.test.ts"],
|
|
);
|
|
assert.ok(inv.records[0].testId.includes("@pkg/a"));
|
|
assert.ok(inv.records[0].testId.includes("proj-a"));
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// diff
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function inv(ids) {
|
|
return { records: ids.map((id) => ({ testId: id })) };
|
|
}
|
|
|
|
test("diff: superset (after ⊇ before) reports no missing", () => {
|
|
const { missing } = diffInventories(inv(["a", "b"]), inv(["a", "b", "c"]));
|
|
assert.deepEqual(missing, []);
|
|
});
|
|
|
|
test("diff: a disappeared test id is reported as missing", () => {
|
|
const { missing, added } = diffInventories(inv(["a", "b", "c"]), inv(["a", "c"]));
|
|
assert.deepEqual(missing, ["b"]);
|
|
assert.deepEqual(added, []);
|
|
});
|
|
|
|
test("diff: a renamed file shows as remove + add", () => {
|
|
const before = inv(["pkg :: old/path.test.ts :: p :: t"]);
|
|
const after = inv(["pkg :: new/path.test.ts :: p :: t"]);
|
|
const { missing, added } = diffInventories(before, after);
|
|
assert.deepEqual(missing, ["pkg :: old/path.test.ts :: p :: t"]);
|
|
assert.deepEqual(added, ["pkg :: new/path.test.ts :: p :: t"]);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// dashboard curated guard
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("curated guard: passes when every file is included or skip-listed", () => {
|
|
const { ok, errors } = validateDashboardCurated({
|
|
includedFiles: new Set(["packages/dashboard/app/a.test.ts"]),
|
|
allTestFiles: ["packages/dashboard/app/a.test.ts", "packages/dashboard/app/b.test.ts"],
|
|
skipList: [{ file: "packages/dashboard/app/b.test.ts", reason: "flaky FN-1" }],
|
|
});
|
|
assert.equal(ok, true, errors.join("; "));
|
|
});
|
|
|
|
test("curated guard: fails on an unregistered (synthetic) test file", () => {
|
|
const { ok, errors } = validateDashboardCurated({
|
|
includedFiles: new Set(["packages/dashboard/app/a.test.ts"]),
|
|
allTestFiles: [
|
|
"packages/dashboard/app/a.test.ts",
|
|
"packages/dashboard/app/synthetic-unregistered.test.ts",
|
|
],
|
|
skipList: [],
|
|
});
|
|
assert.equal(ok, false);
|
|
assert.ok(errors.some((e) => e.includes("synthetic-unregistered.test.ts")));
|
|
});
|
|
|
|
test("curated guard: rejects a skip-list entry with an empty reason", () => {
|
|
const { ok, errors } = validateDashboardCurated({
|
|
includedFiles: new Set(),
|
|
allTestFiles: ["packages/dashboard/app/b.test.ts"],
|
|
skipList: [{ file: "packages/dashboard/app/b.test.ts", reason: " " }],
|
|
});
|
|
assert.equal(ok, false);
|
|
assert.ok(errors.some((e) => e.includes("empty")));
|
|
});
|
|
|
|
test("curated guard: a skip-listed file does not trip the unregistered check", () => {
|
|
const { ok } = validateDashboardCurated({
|
|
includedFiles: new Set(),
|
|
allTestFiles: ["packages/dashboard/app/b.test.ts"],
|
|
skipList: [{ file: "packages/dashboard/app/b.test.ts", reason: "pre-existing failure FN-2" }],
|
|
});
|
|
assert.equal(ok, true);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// end-to-end curated guard against a synthetic temp fixture dir, exercising
|
|
// the real file walk + skip-list validation in one pass (no real repo file).
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("curated guard end-to-end: synthetic unregistered file in a temp dir trips the guard", () => {
|
|
const root = mkdtempSync(join(tmpdir(), "inv-dash-"));
|
|
const appDir = join(root, "app", "__tests__");
|
|
mkdirSync(appDir, { recursive: true });
|
|
const registered = join(appDir, "Registered.test.tsx");
|
|
const synthetic = join(appDir, "SyntheticUnregistered.test.tsx");
|
|
writeFileSync(registered, "test('x', () => {});");
|
|
writeFileSync(synthetic, "test('y', () => {});");
|
|
|
|
// Walk the temp dir the same way the guard does for the real repo.
|
|
const allTestFiles = [
|
|
`app/__tests__/Registered.test.tsx`,
|
|
`app/__tests__/SyntheticUnregistered.test.tsx`,
|
|
];
|
|
|
|
const fail = validateDashboardCurated({
|
|
includedFiles: new Set(["app/__tests__/Registered.test.tsx"]),
|
|
allTestFiles,
|
|
skipList: [],
|
|
});
|
|
assert.equal(fail.ok, false);
|
|
assert.ok(fail.errors.some((e) => e.includes("SyntheticUnregistered.test.tsx")));
|
|
|
|
// Registering it (via skip-list with a reason) makes the guard pass.
|
|
const pass = validateDashboardCurated({
|
|
includedFiles: new Set(["app/__tests__/Registered.test.tsx"]),
|
|
allTestFiles,
|
|
skipList: [
|
|
{ file: "app/__tests__/SyntheticUnregistered.test.tsx", reason: "demo skip FN-3" },
|
|
],
|
|
});
|
|
assert.equal(pass.ok, true, pass.errors.join("; "));
|
|
|
|
rmSync(root, { recursive: true, force: true });
|
|
});
|