import { expect, test } from "bun:test";
import { readFileSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { compileWireFile } from "../../../packages/compiler/src/index.ts";
import { parse as parseWireSyntax } from "../../../packages/syntax/src/parser.ts";
const root = join(import.meta.dir, "..");
const pagesDir = join(root, "app", "pages");
const detailPagesDir = join(pagesDir, "components");
const reference = JSON.parse(
readFileSync(join(root, "..", "..", "packages", "ui", "component-reference.json"), "utf8"),
) as {
count: number;
components: Array<{
name: string;
mount: string;
category: string;
props: Array<{ name: string }>;
slots: string[];
events: string[];
}>;
};
const manifest = JSON.parse(readFileSync(join(root, "showcase-manifest.json"), "utf8")) as {
componentCount: number;
categoryCount: number;
totalDemoCount: number;
components: Array<{
name: string;
mount: string;
slug: string;
category: string;
demoCount: number;
propCount: number;
slots: string[];
events: string[];
profiled: boolean;
}>;
};
const detailSource = (slug: string) => readFileSync(join(detailPagesDir, `${slug}.wrn`), "utf8");
const interactiveOverlayNames = [
"ContextMenu",
"Drawer",
"Dropdown",
"Modal",
"Popover",
"Tooltip",
];
function mountCount(source: string, mount: string): number {
const tag = new RegExp(`<${mount}(?:\\s|>|/)`, "g");
const legacy = new RegExp(`
{
const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as {
devDependencies: Record
;
};
const styles = readFileSync(join(root, "app", "styles", "global.css"), "utf8");
expect(packageJson.devDependencies["@iconify/tailwind4"]).toBeTruthy();
expect(packageJson.devDependencies["@iconify-json/lucide"]).toBeTruthy();
expect(styles).toContain('@plugin "@iconify/tailwind4";');
expect(styles).toContain(".playground-preview-source > .wire-action:not(.w-full)");
expect(styles).toContain('[data-ui-component="MetricGrid"]');
expect(styles).toContain("width: 100%;");
});
test("showcase manifest matches the generated UI reference", () => {
expect(manifest.componentCount).toBe(reference.count);
expect(manifest.components).toHaveLength(reference.count);
expect(manifest.totalDemoCount).toBeGreaterThanOrEqual(reference.count * 3);
expect(new Set(manifest.components.map((component) => component.slug)).size).toBe(
reference.count,
);
for (const component of reference.components) {
const documented = manifest.components.find((entry) => entry.name === component.name);
expect(documented).toBeTruthy();
expect(documented?.mount).toBe(component.mount);
expect(documented?.events).toEqual(component.events);
expect(documented?.slots).toEqual(component.slots);
}
});
test("showcase uses a searchable documentation shell", () => {
const layout = readFileSync(join(root, "app", "layouts", "showcase.wrn"), "utf8");
const styles = readFileSync(join(root, "app", "styles", "global.css"), "utf8");
const runtime = readFileSync(join(root, "public", "playground.js"), "utf8");
expect(layout).toContain("data-docs-directory");
expect(layout).toContain("data-docs-search");
expect(layout.match(/data-docs-component-link/g)).toHaveLength(reference.count);
expect(styles).toContain("grid-template-columns: 17rem minmax(0, 1fr)");
expect(runtime).toContain("data-docs-menu-toggle");
expect(runtime).toContain('event.key.toLowerCase() === "k"');
});
test("showcase SSR document layout maps persisted design cookies to html attributes", () => {
const source = readFileSync(join(root, "app", "layouts", "document.wrn"), "utf8");
expect(source).toContain("");
expect(source).toContain('
');
for (const setting of ["style", "palette", "mode", "font", "scale"]) {
expect(source).toContain(`data-ui-${setting}`);
expect(source).toContain(`cookies['wrn-ui-${setting}']`);
}
});
test("category pages preview every UI component exactly once", () => {
const categoryPages = readdirSync(pagesDir)
.filter((file) => manifest.components.some((component) => `${component.category}.wrn` === file))
.map((file) => readFileSync(join(pagesDir, file), "utf8"))
.join("\n");
const invalidPreviews = reference.components.flatMap((component) => {
const count = mountCount(categoryPages, component.mount);
return count === 1
? []
: [{ name: component.name, mount: component.mount, category: component.category, count }];
});
expect(invalidPreviews).toEqual([]);
});
test("every component has a detail page, playground, and manifest-driven demos", () => {
const files = readdirSync(detailPagesDir).filter((entry) => entry.endsWith(".wrn"));
expect(files).toHaveLength(reference.count);
for (const component of manifest.components) {
const source = detailSource(component.slug);
expect(source).toContain("data-playground-preview");
expect(source).toContain("data-playground-form");
expect(source).toContain("data-playground-code");
expect(source).toContain('href="#playground"');
expect(source.match(/class="demo-workbench"/g)).toHaveLength(component.demoCount);
expect(mountCount(source, component.mount)).toBeGreaterThanOrEqual(component.demoCount + 1);
}
}, 20_000);
test("playgrounds preserve typed values, safe DOM replacement, themes, and event output", () => {
const generator = readFileSync(join(root, "scripts", "generate-showcase.mjs"), "utf8");
const runtime = readFileSync(join(root, "public", "playground.js"), "utf8");
expect(generator).toContain("JSON.parse(");
expect(generator).toContain("Number(");
expect(generator).toContain("data-playground-json");
expect(generator).toContain("prop.name}='{${playgroundStateName(prop)}}'");
expect(generator).toContain('data-slot="${escapeAttribute(slot)}"');
const generatorWithoutDataSlots = generator.replaceAll(
'data-slot="${escapeAttribute(slot)}"',
"",
);
expect(generatorWithoutDataSlots).not.toContain('slot="${escapeAttribute(slot)}"');
expect(runtime).toContain("fetch(url");
expect(runtime).toContain("navigator.clipboard.writeText");
expect(runtime).toContain("preview.replaceChildren");
expect(runtime).not.toContain("preview.innerHTML");
expect(runtime).toContain("__wrnexusHydrateScopes");
expect(runtime).toContain("wireTheme?.bind?.(document)");
expect(runtime).toContain("bindPlaygroundEvents");
expect(runtime).toContain('attributes.push(`${name}="${field.checked}"`)');
});
test("playground enum controls use public profiles instead of inferred implementation comparisons", () => {
const generator = readFileSync(join(root, "scripts", "generate-showcase.mjs"), "utf8");
expect(generator).toContain("profileFor(component.name)?.options?.[prop.name]");
expect(generator).not.toContain("source.matchAll(pattern)");
const pageHeader = manifest.components.find((component) => component.name === "PageHeader");
if (pageHeader) {
const source = detailSource(pageHeader.slug);
expect(source).toContain('name="pg_icon" type="text"');
expect(source).toMatch(/