import { expect, test } from "bun:test";
import { Window } from "happy-dom";
import { renderToStaticMarkup } from "react-dom/server";
import type { ReactNode } from "react";
import { Card } from "./Card";
import { ContainerShowcase } from "./ContainerShowcase";
import { Field } from "./Field";
function render(content: ReactNode) {
const window = new Window();
window.document.body.innerHTML = renderToStaticMarkup(content);
return window.document.body;
}
test("Field connects its label and hint to the rendered control", () => {
const body = render(
{(id, describedBy) => }
,
);
expect(body.querySelector("label")?.htmlFor).toBe("habit");
expect(body.querySelector("input")?.getAttribute("aria-describedby")).toBe("habit-hint");
expect(body.querySelector("#habit-hint")?.textContent).toBe("Keep it short.");
});
test("Field generates unique control IDs and omits absent hint references", () => {
const body = render(<>
{(id, describedBy) => }
{(id, describedBy) => }
>);
const controls = [...body.querySelectorAll("input")];
expect(new Set(controls.map((control) => control.id)).size).toBe(2);
expect(controls.every((control) => !control.hasAttribute("aria-describedby"))).toBe(true);
expect(body.querySelectorAll("small")).toHaveLength(0);
});
test("Card preserves its title styling and accessible name at each heading level", () => {
for (const headingLevel of [2, 3, 4, 5, 6] as const) {
const body = render(Content);
const heading = body.querySelector(`h${headingLevel}.ds-card-title`);
expect(heading?.textContent).toBe("A clear boundary");
expect(body.querySelector("article")?.getAttribute("aria-labelledby")).toBe(heading?.id);
}
expect(render().querySelector("h3")?.textContent).toBe("Default");
});
test("Layout uses subsection headings above the card titles", () => {
const body = render();
expect(body.querySelectorAll("h2")).toHaveLength(1);
expect(body.querySelectorAll("h3")).toHaveLength(2);
expect(body.querySelectorAll("h4.ds-card-title")).toHaveLength(6);
});