201 lines
6.8 KiB
TypeScript
201 lines
6.8 KiB
TypeScript
/**
|
|
* Tests for `check-registry-eject.ts`.
|
|
*
|
|
* Builds fixtures filesystems on disk under `mkdtemp` and exercises
|
|
* the exported helpers (`audit`, `loadEntry`) directly. The script's
|
|
* `main()` is exercised indirectly through these helpers — its
|
|
* top-level behaviour (process.exit) is covered by the lint gate
|
|
* itself running on real source.
|
|
*/
|
|
|
|
import { afterEach, beforeEach, describe, expect, it } from "@suaveplan/testing/runner";
|
|
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { audit, loadEntry } from "./check-registry-eject.js";
|
|
|
|
let workDir: string;
|
|
|
|
beforeEach(async () => {
|
|
workDir = await mkdtemp(join(tmpdir(), "registry-eject-"));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await rm(workDir, { recursive: true, force: true });
|
|
});
|
|
|
|
async function writeJson(rel: string, body: unknown): Promise<string> {
|
|
const full = join(workDir, rel);
|
|
await mkdir(join(full, ".."), { recursive: true });
|
|
await writeFile(full, JSON.stringify(body, null, 2), "utf8");
|
|
return full;
|
|
}
|
|
|
|
async function writeFixture(rel: string, content = ""): Promise<string> {
|
|
const full = join(workDir, rel);
|
|
await mkdir(join(full, ".."), { recursive: true });
|
|
await writeFile(full, content, "utf8");
|
|
return full;
|
|
}
|
|
|
|
describe("loadEntry", () => {
|
|
it("loads a valid registry entry", { timeout: 5000 }, async () => {
|
|
const entry = await writeJson("button.json", {
|
|
name: "@suaveplan/button",
|
|
type: "registry:ui",
|
|
files: [{ path: "button.tsx", type: "registry:ui" }],
|
|
});
|
|
const result = await loadEntry(entry);
|
|
expect("error" in result).toBe(false);
|
|
});
|
|
|
|
it("rejects an entry without a name", { timeout: 5000 }, async () => {
|
|
const entry = await writeJson("bad.json", {
|
|
type: "registry:ui",
|
|
files: [],
|
|
});
|
|
const result = await loadEntry(entry);
|
|
expect("error" in result).toBe(true);
|
|
});
|
|
|
|
it("rejects an entry with non-array files", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const entry = await writeJson("bad.json", {
|
|
name: "x",
|
|
type: "registry:ui",
|
|
files: "oops",
|
|
});
|
|
const result = await loadEntry(entry);
|
|
expect("error" in result).toBe(true);
|
|
});
|
|
|
|
it("rejects malformed JSON", { timeout: 5000 }, async () => {
|
|
const entry = await writeFixture("bad.json", "{ not json");
|
|
const result = await loadEntry(entry);
|
|
expect("error" in result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("audit", () => {
|
|
it("returns no diagnostics on a clean fixtures tree", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await writeFixture("src/components/button/button.tsx", "export {}");
|
|
const entry = await writeJson("registry/r/button.json", {
|
|
name: "@x/button",
|
|
type: "registry:ui",
|
|
files: [{ path: "button.tsx", type: "registry:ui" }],
|
|
});
|
|
const diagnostics = await audit({
|
|
registryEntries: [entry],
|
|
componentDirs: ["button"],
|
|
componentsDir,
|
|
});
|
|
expect(diagnostics).toEqual([]);
|
|
});
|
|
|
|
it("flags a component directory with no registry entry", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await writeFixture("src/components/button/button.tsx", "export {}");
|
|
const diagnostics = await audit({
|
|
registryEntries: [],
|
|
componentDirs: ["button"],
|
|
componentsDir,
|
|
});
|
|
expect(
|
|
diagnostics.find(
|
|
(d) => d.kind === "MISSING_REGISTRY_ENTRY"
|
|
)?.message
|
|
).toMatch(/button/);
|
|
});
|
|
|
|
it("flags a registry entry whose source file is missing", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await mkdir(join(componentsDir, "ghost"), { recursive: true });
|
|
const entry = await writeJson("registry/r/ghost.json", {
|
|
name: "@x/ghost",
|
|
type: "registry:ui",
|
|
files: [{ path: "ghost.tsx", type: "registry:ui" }],
|
|
});
|
|
const diagnostics = await audit({
|
|
registryEntries: [entry],
|
|
componentDirs: ["ghost"],
|
|
componentsDir,
|
|
});
|
|
expect(
|
|
diagnostics.find((d) => d.kind === "MISSING_SOURCE_FILE")?.message
|
|
).toMatch(/ghost\.tsx/);
|
|
});
|
|
|
|
it("flags an orphan registry entry (no matching component dir)", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await writeFixture(
|
|
"src/components/button/button.tsx",
|
|
"export {}"
|
|
);
|
|
const entryButton = await writeJson("registry/r/button.json", {
|
|
name: "@x/button",
|
|
type: "registry:ui",
|
|
files: [{ path: "button.tsx", type: "registry:ui" }],
|
|
});
|
|
const entryStale = await writeJson("registry/r/removed.json", {
|
|
name: "@x/removed",
|
|
type: "registry:ui",
|
|
files: [{ path: "removed.tsx", type: "registry:ui" }],
|
|
});
|
|
const diagnostics = await audit({
|
|
registryEntries: [entryButton, entryStale],
|
|
componentDirs: ["button"],
|
|
componentsDir,
|
|
});
|
|
expect(
|
|
diagnostics.find(
|
|
(d) => d.kind === "ORPHAN_REGISTRY_ENTRY"
|
|
)?.message
|
|
).toMatch(/removed/);
|
|
});
|
|
|
|
it("flags an entry with empty files[]", { timeout: 5000 }, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await writeFixture("src/components/foo/foo.tsx", "export {}");
|
|
const entry = await writeJson("registry/r/foo.json", {
|
|
name: "@x/foo",
|
|
type: "registry:ui",
|
|
files: [],
|
|
});
|
|
const diagnostics = await audit({
|
|
registryEntries: [entry],
|
|
componentDirs: ["foo"],
|
|
componentsDir,
|
|
});
|
|
expect(
|
|
diagnostics.find((d) => d.kind === "EMPTY_FILES_LIST")?.message
|
|
).toMatch(/foo\.json/);
|
|
});
|
|
|
|
it("flags malformed JSON entries", { timeout: 5000 }, async () => {
|
|
const componentsDir = join(workDir, "src/components");
|
|
await writeFixture("src/components/foo/foo.tsx", "");
|
|
const entry = await writeFixture(
|
|
"registry/r/foo.json",
|
|
"{ not json"
|
|
);
|
|
const diagnostics = await audit({
|
|
registryEntries: [entry],
|
|
componentDirs: ["foo"],
|
|
componentsDir,
|
|
});
|
|
expect(
|
|
diagnostics.find((d) => d.kind === "MALFORMED_ENTRY")?.message
|
|
).toMatch(/foo\.json/);
|
|
});
|
|
});
|