import { describe, it, expect } from "vitest"; import { readdirSync, readFileSync, statSync } from "node:fs"; import { join, relative } from "node:path"; /** * Static guard: no production `.tsx` file may pass `showCloseButton` * to ``. * * Why: the shared DialogFooter renders an EXTRA outline-styled * when `showCloseButton` is set. Every dialog * we have that already provides its own primary action also includes * a Cancel/dismiss button (either via DialogClose or by closing the * Dialog state on submit) — and Radix's auto-rendered corner X * already gives users a third way out. The redundant Close button * cluttered the footer and shipped to production multiple times * before this guard existed; this test stops it from regressing. */ const SRC_ROOT = join(__dirname, ".."); function listTsxFiles(dir: string): string[] { const out: string[] = []; for (const entry of readdirSync(dir)) { const full = join(dir, entry); const st = statSync(full); if (st.isDirectory()) { out.push(...listTsxFiles(full)); } else if (entry.endsWith(".tsx")) { out.push(full); } } return out; } interface Hit { file: string; line: number; excerpt: string; } function findHits(content: string): Array<{ line: number; excerpt: string }> { const hits: Array<{ line: number; excerpt: string }> = []; // Match `` so we don't accidentally cross into the // children. Multi-line opening tags are handled by `[\s\S]`. const matches = content.matchAll( //g, ); for (const m of matches) { const idx = m.index ?? 0; const line = content.slice(0, idx).split("\n").length; hits.push({ line, excerpt: m[0].slice(0, 120).replace(/\s+/g, " ") }); } return hits; } describe("static guard: no ", () => { // Skip this test file (it intentionally contains the pattern strings) // and all other .test.tsx files (they're examples, not production UI). const files = listTsxFiles(SRC_ROOT).filter( (f) => !/\.test\.tsx?$/.test(f), ); it("scans at least one source file (sanity)", () => { expect(files.length).toBeGreaterThan(0); }); it("finds no in any production .tsx file", () => { const allHits: Hit[] = []; for (const file of files) { const content = readFileSync(file, "utf8"); for (const h of findHits(content)) { allHits.push({ file: relative(SRC_ROOT, file), ...h }); } } if (allHits.length > 0) { const message = allHits .map((h) => ` ${h.file}:${h.line} → ${h.excerpt}`) .join("\n"); throw new Error( `Redundant Close button detected — :\n${message}\n` + `The DialogFooter component injects an extra "Close" button when this prop\n` + `is set. Every existing caller already has its own Cancel/Close action plus\n` + `Radix's corner X — a third Close is just visual noise. Remove the prop.`, ); } expect(allHits).toEqual([]); }); }); describe("findHits parser", () => { it("matches a single-line ", () => { expect( findHits("foo"), ).toHaveLength(1); }); it("matches when other props are present alongside showCloseButton", () => { expect( findHits(''), ).toHaveLength(1); }); it("matches across multiple lines", () => { const src = ``; expect(findHits(src)).toHaveLength(1); }); it("does NOT match a clean ", () => { expect(findHits("x")).toHaveLength(0); }); it("does NOT match a similarly-named prop on an unrelated component", () => { expect(findHits("")).toHaveLength(0); }); });