- 51 headless Web Components (45 core + 6 animation) - Shared helpers: emit(), part(), listen(), wireLabel(), initialValue() - Zero `new CustomEvent` or `static #counter` — all use shared utils - Zod schemas for all 44 core components - MCP package with discover, inspect, compose, validate tools - Showcase with Aperture Science theme, M3 Expressive motion - 81 tests passing, TypeScript strict mode clean - Signals (~500B), SPA router (~400B), zero dependencies
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
import { describe, it, expect, beforeEach } from "vitest";
|
|
import { PettySelect } from "../src/components/select/index";
|
|
import { h } from "./helpers";
|
|
|
|
describe("petty-select", () => {
|
|
let el: PettySelect;
|
|
|
|
beforeEach(() => {
|
|
document.body.textContent = "";
|
|
el = document.createElement("petty-select") as PettySelect;
|
|
el.setAttribute("default-value", "apple");
|
|
const trigger = h("button", { "data-part": "trigger" }, "Pick a fruit");
|
|
const opt1 = h("petty-select-option", { value: "apple" }, "Apple");
|
|
const opt2 = h("petty-select-option", { value: "banana" }, "Banana");
|
|
const listbox = h("div", { id: "fruit-list", popover: "", "data-part": "listbox", role: "listbox" }, opt1, opt2);
|
|
const hidden = h("input", { type: "hidden", name: "fruit" });
|
|
el.appendChild(trigger);
|
|
el.appendChild(listbox);
|
|
el.appendChild(hidden);
|
|
document.body.appendChild(el);
|
|
});
|
|
|
|
it("registers the custom elements", () => {
|
|
expect(customElements.get("petty-select")).toBe(PettySelect);
|
|
expect(customElements.get("petty-select-option")).toBeDefined();
|
|
});
|
|
|
|
it("initializes with default-value", () => {
|
|
expect(el.value).toBe("apple");
|
|
});
|
|
|
|
it("sets aria-haspopup on trigger", () => {
|
|
const trigger = el.querySelector("[data-part=trigger]")!;
|
|
expect(trigger.getAttribute("aria-haspopup")).toBe("listbox");
|
|
expect(trigger.getAttribute("aria-expanded")).toBe("false");
|
|
});
|
|
|
|
it("syncs hidden input value", () => {
|
|
const input = el.querySelector("input[type=hidden]") as HTMLInputElement;
|
|
expect(input.value).toBe("apple");
|
|
});
|
|
|
|
it("marks selected option with aria-selected true", () => {
|
|
const apple = el.querySelector("[value=apple]")!;
|
|
const banana = el.querySelector("[value=banana]")!;
|
|
expect(apple.getAttribute("aria-selected")).toBe("true");
|
|
expect(banana.getAttribute("aria-selected")).toBe("false");
|
|
});
|
|
});
|