feat(ui): add navigation and picker primitives
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { DatePicker } from "./date-picker";
|
||||
|
||||
describe("DatePicker", () => {
|
||||
it("renders a placeholder and selects a date in uncontrolled mode", async () => {
|
||||
render(
|
||||
<DatePicker
|
||||
aria-label="Launch date"
|
||||
defaultOpen
|
||||
placeholder="Pick launch date"
|
||||
/>
|
||||
);
|
||||
|
||||
const field = screen.getByRole("combobox", { name: "Launch date" });
|
||||
expect(field.closest('[data-slot="root"]')).toHaveAttribute("data-placeholder", "");
|
||||
|
||||
const calendar = screen.getByRole("grid");
|
||||
const dayButton = within(calendar).getAllByRole("gridcell")[10];
|
||||
|
||||
fireEvent.click(dayButton);
|
||||
|
||||
expect(field.closest('[data-slot="root"]')).not.toHaveAttribute("data-placeholder");
|
||||
expect(field).not.toHaveValue("");
|
||||
});
|
||||
|
||||
it("supports controlled values and emits changes", async () => {
|
||||
const onValueChange = vi.fn();
|
||||
|
||||
render(
|
||||
<DatePicker
|
||||
aria-label="Controlled launch date"
|
||||
defaultOpen
|
||||
onValueChange={onValueChange}
|
||||
value={new Date(2026, 3, 18)}
|
||||
/>
|
||||
);
|
||||
|
||||
fireEvent.click(
|
||||
screen.getByRole("gridcell", {
|
||||
name: /Apr 20, 2026|20 Apr 2026|Apr 20 2026/i
|
||||
})
|
||||
);
|
||||
|
||||
expect(onValueChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supports clearing the current value and choosing today", async () => {
|
||||
render(
|
||||
<DatePicker
|
||||
aria-label="Review date"
|
||||
defaultOpen
|
||||
defaultValue={new Date(2026, 4, 9)}
|
||||
/>
|
||||
);
|
||||
|
||||
const field = screen.getByRole("combobox", { name: "Review date" });
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Clear date" }));
|
||||
|
||||
expect(field).toHaveValue("");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Today" }));
|
||||
|
||||
expect(field).not.toHaveValue("");
|
||||
});
|
||||
|
||||
it("supports month switching via controls and year selection", async () => {
|
||||
render(
|
||||
<DatePicker
|
||||
aria-label="Window date"
|
||||
defaultMonth={new Date(2026, 2, 1)}
|
||||
defaultOpen
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("March 2026")).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Next month" }));
|
||||
expect(screen.getByText("April 2026")).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole("combobox", { name: "Year" }));
|
||||
fireEvent.click(screen.getByRole("option", { name: "2028" }));
|
||||
|
||||
expect(screen.getByText("April 2028")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("respects min and max dates", async () => {
|
||||
render(
|
||||
<DatePicker
|
||||
aria-label="Guardrailed date"
|
||||
defaultMonth={new Date(2026, 2, 1)}
|
||||
defaultOpen
|
||||
maxDate={new Date(2026, 2, 20)}
|
||||
minDate={new Date(2026, 2, 10)}
|
||||
/>
|
||||
);
|
||||
|
||||
const disabledDays = screen
|
||||
.getAllByRole("gridcell")
|
||||
.filter((cell) => cell.hasAttribute("data-disabled"));
|
||||
|
||||
expect(disabledDays.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user