test(guards): make path-pinned source reads fail when their subject moves

A test that reads a source file by path and asserts an absence
(`expect(source).not.toMatch(…)`) stays green after a split: the code it
watched moved next door and the old path no longer holds it. A missing file
throws; a file that kept its name but lost its contents does not.

- `readSource(path, anchors)` in helpers/source-files.ts reads one file and
  requires every anchor (a string or pattern the watched code carries) to
  match at least once; it throws on a missing file, a lost anchor, or a read
  without an anchor.
- `readSourceFolder(dir, { floor })` is the folder-scan form for a subject
  that was split into several files.
- The twelve reads that were asserted only negatively now go through
  `readSource` with an anchor: the batch route, the integration-sync
  registrar, the dashboard client, the mood insights client, the sleep
  overview and sleep page, the sidebar, the baseline form, the account
  section (two guards), api-handler's requireAuth and the Google Health sync.
- The two schema parsers the wipe and enum guards share now refuse a parse
  of the real schema that finds fewer than 50 models (and 10 enums), so a
  moved file or a drifted block regex cannot leave those guards comparing
  an allowlist against nothing. Synthetic schemas a test writes stay exempt.

Proof: renaming `setSaving` in the baseline form made the converted
confirm-failure guard throw "the file no longer contains setSaving"; the
helper's own test plants a missing file, a lost string anchor, a lost regex
anchor, an empty anchor list and an under-floor folder, each of which throws.
This commit is contained in:
Marc-André Bombeck committed 2026-10-22 04:29:35 +02:00
1 parent c86c7d1a79
commit f3d7ab31e2
16 files changed
+204 -44

No files matched your search

+4 -5
View File
@@ -40,6 +40,7 @@ import { DELETE } from "../[id]/route";
import { requireAuth } from "@/lib/api-handler";
import { prisma } from "@/lib/db";
import { isApiGloballyEnabled } from "@/lib/app-settings";
import { readSource } from "@/__tests__/helpers/source-files";
const USER = { id: "user-1", username: "u" };
@@ -168,11 +169,9 @@ describe("the switch and the authentication path", () => {
// a token would NOT be live during the outage and hiding the list would
// stop being wrong. This reads the source because the behaviour is an
// absence, and an absence has no call to spy on.
const { readFileSync } = await import("node:fs");
const { join } = await import("node:path");
const source = readFileSync(
join(process.cwd(), "src/lib/api-handler.ts"),
"utf8",
const source = readSource(
"src/lib/api-handler.ts",
"export async function requireAuth(",
);
expect(source).not.toContain("isApiGloballyEnabled");
expect(source).not.toContain("apiGlobal");