Mats Bosson 8f075f1792 feat: add 12 components — Tooltip, Popover, HoverCard, Alert, Badge,
Skeleton, Breadcrumbs, Link, Button, Image, Meter, NumberField
Floating components: Tooltip (hover/focus), Popover (click, with focus
trap and dismiss), HoverCard (hover with safe area).
Simple components: Alert (role=alert), Badge (role=status), Skeleton
(loading placeholder with data attributes).
Navigation: Breadcrumbs (nav>ol>li with separators), Link (accessible
anchor with disabled), Button (with disabled click suppression).
Data/Form: Image (Img+Fallback with loading status), Meter (like
Progress for known ranges), NumberField (spinbutton with inc/dec).
302 tests across 46 files, typecheck clean, build produces 176 files.
2026-03-29 19:34:13 +07:00

80 lines
2.5 KiB
TypeScript

import { fireEvent, render, screen } from "@solidjs/testing-library";
import { describe, expect, it, vi } from "vitest";
import { NumberField } from "../../../src/components/number-field/index";
describe("NumberField basics", () => {
it("input has role=spinbutton", () => {
render(() => (
<NumberField>
<NumberField.Input />
</NumberField>
));
expect(screen.getByRole("spinbutton")).toBeTruthy();
});
it("sets aria-valuenow", () => {
render(() => (
<NumberField defaultValue={5}>
<NumberField.Input />
</NumberField>
));
expect(screen.getByRole("spinbutton").getAttribute("aria-valuenow")).toBe("5");
});
it("label linked to input", () => {
render(() => (
<NumberField>
<NumberField.Label>Quantity</NumberField.Label>
<NumberField.Input />
</NumberField>
));
const label = screen.getByText("Quantity");
const input = screen.getByRole("spinbutton");
expect(label.getAttribute("for")).toBe(input.id);
});
});
describe("NumberField interactions", () => {
it("increment button increases value", () => {
const onChange = vi.fn();
render(() => (
<NumberField defaultValue={5} onValueChange={onChange}>
<NumberField.Input />
<NumberField.IncrementTrigger>+</NumberField.IncrementTrigger>
</NumberField>
));
fireEvent.click(screen.getByText("+"));
expect(onChange).toHaveBeenCalledWith(6);
});
it("decrement button decreases value", () => {
const onChange = vi.fn();
render(() => (
<NumberField defaultValue={5} onValueChange={onChange}>
<NumberField.Input />
<NumberField.DecrementTrigger>-</NumberField.DecrementTrigger>
</NumberField>
));
fireEvent.click(screen.getByText("-"));
expect(onChange).toHaveBeenCalledWith(4);
});
it("respects min/max", () => {
const onChange = vi.fn();
render(() => (
<NumberField defaultValue={10} max={10} onValueChange={onChange}>
<NumberField.Input />
<NumberField.IncrementTrigger>+</NumberField.IncrementTrigger>
</NumberField>
));
fireEvent.click(screen.getByText("+"));
expect(onChange).not.toHaveBeenCalled();
});
it("ArrowUp increments", () => {
const onChange = vi.fn();
render(() => (
<NumberField defaultValue={5} onValueChange={onChange}>
<NumberField.Input />
</NumberField>
));
fireEvent.keyDown(screen.getByRole("spinbutton"), { key: "ArrowUp" });
expect(onChange).toHaveBeenCalledWith(6);
});
});