Mats Bosson 796ccab838 Slider component
Implements headless Slider with Root, Track, Range, and Thumb parts. Supports controlled/uncontrolled value, keyboard navigation (Arrow, Page, Home, End), clamping, step, orientation, and disabled state. 10 tests added, all 152 suite tests pass.
2026-03-29 08:30:31 +07:00

121 lines
3.9 KiB
TypeScript

// packages/core/tests/components/slider/slider.test.tsx
import { fireEvent, render, screen } from "@solidjs/testing-library";
import { describe, expect, it } from "vitest";
import { Slider } from "../../../src/components/slider/index";
describe("Slider", () => {
it("thumb has role=slider", () => {
render(() => (
<Slider defaultValue={50}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
expect(screen.getByRole("slider")).toBeTruthy();
});
it("thumb has correct aria attributes", () => {
render(() => (
<Slider defaultValue={50} min={0} max={100}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
expect(thumb.getAttribute("aria-valuenow")).toBe("50");
expect(thumb.getAttribute("aria-valuemin")).toBe("0");
expect(thumb.getAttribute("aria-valuemax")).toBe("100");
});
it("ArrowRight increases value by step", () => {
render(() => (
<Slider defaultValue={50} step={5}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "ArrowRight" });
expect(thumb.getAttribute("aria-valuenow")).toBe("55");
});
it("ArrowLeft decreases value by step", () => {
render(() => (
<Slider defaultValue={50} step={5}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "ArrowLeft" });
expect(thumb.getAttribute("aria-valuenow")).toBe("45");
});
it("Home sets value to min", () => {
render(() => (
<Slider defaultValue={50} min={10} max={100}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "Home" });
expect(thumb.getAttribute("aria-valuenow")).toBe("10");
});
it("End sets value to max", () => {
render(() => (
<Slider defaultValue={50} min={0} max={100}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "End" });
expect(thumb.getAttribute("aria-valuenow")).toBe("100");
});
it("value is clamped at max", () => {
render(() => (
<Slider defaultValue={95} max={100} step={10}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "ArrowRight" });
expect(thumb.getAttribute("aria-valuenow")).toBe("100");
});
it("value is clamped at min", () => {
render(() => (
<Slider defaultValue={5} min={0} step={10}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "ArrowLeft" });
expect(thumb.getAttribute("aria-valuenow")).toBe("0");
});
it("controlled value", () => {
render(() => (
<Slider value={30} onValueChange={() => {}}>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
expect(screen.getByRole("slider").getAttribute("aria-valuenow")).toBe("30");
});
it("disabled thumb does not respond to keyboard", () => {
render(() => (
<Slider defaultValue={50} disabled>
<Slider.Track><Slider.Range /><Slider.Thumb /></Slider.Track>
</Slider>
));
const thumb = screen.getByRole("slider");
thumb.focus();
fireEvent.keyDown(thumb, { key: "ArrowRight" });
expect(thumb.getAttribute("aria-valuenow")).toBe("50");
});
});