import { expect, test } from "bun:test"; import { readFileSync } from "node:fs"; import { join } from "node:path"; import { compileWireFile } from "../../compiler/src/index.ts"; import { uiComponentNames, uiComponentsDir, uiCss } from "../src/index.ts"; test("bundled UI assets are discoverable and readable", () => { expect(uiComponentNames()).toContain("Button"); expect(uiComponentNames()).toContain("FAQAccordion"); expect(uiComponentNames()).toContain("AnnouncementBar"); expect(uiComponentNames()).toContain("BackToTop"); expect(readFileSync(join(uiComponentsDir(), "Button.wrn"), "utf8")).toContain("component Button"); expect(uiCss()).toContain("--wire-"); }); test("generated component reference documents every bundled component and its props", () => { const reference = JSON.parse( readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), ) as { count: number; components: Array<{ name: string; props: Array<{ name: string }> }> }; expect(reference.count).toBe(uiComponentNames().length); expect(reference.count).toBeGreaterThanOrEqual(891); expect(reference.components.map((component) => component.name)).toEqual( expect.arrayContaining(uiComponentNames()), ); expect(reference.components.find((component) => component.name === "Button")?.props).toEqual( expect.arrayContaining([expect.objectContaining({ name: "label" })]), ); }); test("PDF minimum-release and essential build-first components are bundled", () => { const required = [ "Typography", "Form", "FormLabel", "FormHelpText", "FormError", "LoadingButton", "Combobox", "MultiSelect", "TimePicker", "DateTimePicker", "RecurringSchedulePicker", "QuietHoursPicker", "ConfirmationDialog", "DataTable", "FilterBar", "MegaMenu", "DesktopNavigation", "ProductsMegaMenu", "MobileNavigation", "MarketingPageShell", "ProductPageShell", "LegalPageShell", "ProductCard", "MetricGrid", "FAQ", "PricingComparisonTable", "SDKTabs", "LegalTableOfContents", "CookiePreferencesDialog", ]; expect(uiComponentNames()).toEqual(expect.arrayContaining(required)); }); test("component-system CSS includes responsive, theme-token, focus, and reduced-motion rules", () => { const css = uiCss(); expect(css).toContain("@media (max-width: 768px)"); expect(css).toContain("@media (max-width: 480px)"); expect(css).toContain("@media (prefers-reduced-motion: reduce)"); expect(css).toContain(":focus-visible"); expect(css).toContain("var(--wire-color-surface)"); expect(css).toContain("min-height: 44px"); expect(css).toContain("--wire-motion-base"); expect(css).toContain("--wire-ease-emphasized"); expect(css).toContain("@keyframes wire-component-enter"); expect(css).toContain("@keyframes wire-dialog-enter"); expect(css).toContain("@media (hover: hover) and (pointer: fine)"); expect(css).toContain("--color-violet-600: var(--wire-color-primary)"); expect(css).toContain("--color-blue-600: var(--wire-color-info)"); expect(css).toContain("--color-red-600: var(--wire-color-danger)"); expect(css).toMatch(/:root\s*\{[^}]*--color-violet-600: var\(--wire-color-primary\)/s); expect(css).toContain(".wire-bg-primary"); expect(css).toContain(".wire-text-muted"); expect(css).toContain(".wire-visually-hidden"); expect(css).toContain(".wire-catalog-card--channel::before"); expect(css).toContain(".wire-catalog-card--integration::before"); }); test("page shells leave background ownership to the page", () => { const css = uiCss(); const shellRule = css.match(/\.wire-page-shell\s*\{([^}]*)\}/)?.[1] ?? ""; expect(shellRule).not.toMatch(/background(?:-color)?\s*:/); }); test("component boundaries have no default margins and expose class customization", () => { for (const name of uiComponentNames()) { const source = readFileSync(join(uiComponentsDir(), `${name}.wrn`), "utf8"); const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; expect(classes.filter((token) => /^-?m[trblxy]?-/.test(token))).toEqual([]); expect(source).toMatch(/^\s*(?:class|className)\s*(?::[^=\r\n]+)?=/m); expect(root).toMatch(/\{class(?:Name)?\}/); } }); test("layout boundaries do not add default padding", () => { for (const name of [ "Container", "CTASection", "EmptyState", "ErrorState", "Hero", "LegalDocumentLayout", "TimelineItem", ]) { const source = readFileSync(join(uiComponentsDir(), `${name}.wrn`), "utf8"); const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; expect(classes.filter((token) => /^p[trblxy]?-/.test(token))).toEqual([]); } }); test("every bundled UI component compiles", () => { for (const name of uiComponentNames()) { const path = join(uiComponentsDir(), `${name}.wrn`); expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow(); } });