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"; 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<{ mount: string; category: string }>; }; test("showcase configures local Lucide icon generation", () => { 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("width: fit-content;"); }); test("showcase uses a searchable three-column 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("advanced select demos use validation schemas and a real remote API", () => { const page = readFileSync( join(root, "app", "pages", "components", "advanced-select.wrn"), "utf8", ); expect(page).toContain('data-schema="advanced-select-validation"'); expect(page).toContain('data-schema="advanced-select-dynamic-validation"'); expect(readFileSync(join(root, "app", "api", "teams.ts"), "utf8")).toContain("export const GET"); }); test("category pages preview every UI component exactly once", () => { const categoryPages = readdirSync(pagesDir) .filter((file) => file !== "index.wrn" && file.endsWith(".wrn")) .map((file) => readFileSync(join(pagesDir, file), "utf8")) .join("\n"); const mounts = [...categoryPages.matchAll(/
match[1], ); expect(mounts).toHaveLength(reference.count); expect(new Set(mounts).size).toBe(reference.count); expect(mounts.sort()).toEqual(reference.components.map((component) => component.mount).sort()); }); test("every component has a detail page with its expected live use cases", () => { const files = readdirSync(detailPagesDir).filter((entry) => entry.endsWith(".wrn")); expect(files).toHaveLength(reference.count); const detailMounts = files.flatMap((file) => { const source = readFileSync(join(detailPagesDir, file), "utf8"); return [...source.matchAll(/
match[1]); }); // Every detail page has one playground plus three standard demos. Interactive // components add specialized capability demos beyond that shared baseline. expect(detailMounts).toHaveLength(reference.count * 4 + 95); for (const component of reference.components) { const expectedMounts = component.mount === "Button" ? 9 : component.mount === "AdvancedSelect" ? 42 : component.mount === "ComboBox" ? 22 : component.mount === "InputNumber" ? 13 : component.mount === "PinInput" ? 19 : component.mount === "StrongPassword" ? 7 : component.mount === "TogglePassword" ? 11 : 4; expect(detailMounts.filter((mount) => mount === component.mount)).toHaveLength(expectedMounts); } }, 15_000); test("every detail page has a type-aware realtime playground", () => { const files = readdirSync(detailPagesDir).filter((entry) => entry.endsWith(".wrn")); for (const file of files) { const source = readFileSync(join(detailPagesDir, file), "utf8"); expect(source).toContain("data-playground-preview"); expect(source).toContain("data-playground-form"); expect(source).toContain("data-playground-code"); expect(source).toContain("data-playground-copy"); expect(source).toContain('href="#playground"'); } const runtime = readFileSync(join(root, "public", "playground.js"), "utf8"); expect(runtime).toContain("fetch(url"); expect(runtime).toContain("HTMLSelectElement"); expect(runtime).toContain("navigator.clipboard.writeText"); expect(runtime).toContain("updateCode(playground)"); expect(runtime).toContain("__wrnexusHydrateScopes"); expect(runtime).toContain("data-playground-json"); expect(runtime).toContain('createPolicy("wrnexus-playground"'); expect(runtime).toContain("preview.replaceChildren"); expect(runtime).not.toContain("preview.innerHTML"); }); test("detail pages show component syntax beside each live preview", () => { const buttonPage = readFileSync(join(detailPagesDir, "button.wrn"), "utf8"); expect(buttonPage).toContain('name="pg_label" type="text"'); expect(buttonPage).toContain('name="pg_variant"'); expect(buttonPage).toContain(''); expect(buttonPage).not.toContain(''); expect(buttonPage).toContain('name="pg_color"'); expect(buttonPage).toContain(''); expect(buttonPage).toContain('name="pg_size"'); expect(buttonPage).toContain(''); expect(buttonPage.match(/class="demo-workbench"/g)).toHaveLength(8); expect(buttonPage.match(/<Button/g)).toHaveLength(9); expect(buttonPage).not.toContain("<div data-component="Button""); expect(buttonPage).not.toContain('
'); }); test("advanced select and combobox document their complete event contract", () => { for (const slug of ["advanced-select", "combo-box"]) { const source = readFileSync(join(detailPagesDir, `${slug}.wrn`), "utf8"); for (const event of ["search", "select", "change", "clear", "open", "close", "load", "error"]) { expect(source).toContain(`@${event}`); } expect(source).toContain('id="events"'); expect(source).toContain("event.detail"); } }); test("pin input documents verification events", () => { const source = readFileSync(join(detailPagesDir, "pin-input.wrn"), "utf8"); for (const event of ["input", "change", "complete", "paste", "clear", "error"]) { expect(source).toContain(`@${event}`); } expect(source).toContain('id="events"'); expect(source).toContain("event.detail"); expect(source).toContain("Different lengths"); expect(source).toContain('length="3"'); expect(source).toContain('length="5"'); expect(source).toContain('length="7"'); }); test("toggle password documents visibility states, validation, and declared events", () => { const source = readFileSync(join(detailPagesDir, "toggle-password.wrn"), "utf8"); for (const event of ["input", "change", "toggle"]) { expect(source).toContain(`@${event}`); } expect(source).toContain("Checkbox-controlled toggle"); expect(source).toContain("Synchronized password fields"); expect(source).toContain("Without visibility toggle"); expect(source).toContain("fields='[\n {"); expect(source).toContain('"label": "New password"'); expect(source).toContain('"name": "current-password"'); expect(source).not.toContain("fields='[..]'"); expect(source).toContain('data-schema="toggle-password-validation"'); }); test("strong password documents live scoring, requirements, popover, and custom characters", () => { const source = readFileSync(join(detailPagesDir, "strong-password.wrn"), "utf8"); expect(source).toContain("Live strength meter"); expect(source).toContain("Requirements and hint text"); expect(source).toContain("Requirements in a popover"); expect(source).toContain("Custom special characters"); expect(source).toContain('presentation="popover"'); expect(source).toContain('specialCharactersSet="@#_-."'); for (const event of ["input", "change", "strength"]) { expect(source).toContain(`@${event}`); } }); test("complex component props are shown as complete readable multiline values", () => { for (const slug of ["advanced-select", "combo-box", "select", "toggle-password"]) { const source = readFileSync(join(detailPagesDir, `${slug}.wrn`), "utf8"); expect(source).not.toMatch(/\b(?:options|groups|items|fields)='\[\.\.\.\]'/); } const advancedSelect = readFileSync(join(detailPagesDir, "advanced-select.wrn"), "utf8"); expect(advancedSelect).toContain("options='[\n {"); expect(advancedSelect).toContain('"value": "design"'); }); test("code examples preserve literal object braces after client hydration", () => { const source = readFileSync(join(detailPagesDir, "toggle-password.wrn"), "utf8"); expect(source).toContain("{"); expect(source).toContain("}"); expect(source).not.toContain('fields=\'[\n {\n "label"'); }); test("every generated showcase page compiles", () => { const paths = [ ...readdirSync(pagesDir) .filter((entry) => entry.endsWith(".wrn")) .map((entry) => join(pagesDir, entry)), ...readdirSync(detailPagesDir) .filter((entry) => entry.endsWith(".wrn")) .map((entry) => join(detailPagesDir, entry)), ]; for (const path of paths) { expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow(); } });