Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 64 additions & 10 deletions packages/ui/src/atoms/calendar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { Calendar } from "./calendar";

/**
* In range mode the opening view comes from `rangeValue` / `defaultRangeValue`;
* with an empty range it falls back to today. Every literal date below is only
* rendered while the clock sits in July 2026, so pin it — otherwise these specs
* pass during July and fail in every other month.
*/
const JULY_2026 = new Date(2026, 6, 15, 12, 0, 0);

beforeEach(() => {
vi.useFakeTimers({ shouldAdvanceTime: true });
vi.setSystemTime(JULY_2026);
});

afterEach(() => {
vi.useRealTimers();
});

const setupUser = () =>
userEvent.setup({ advanceTimers: vi.advanceTimersByTime });

/**
* user-event treats a null target as a no-op instead of throwing, which turns a
* missing day cell into a silently passing assertion. Fail loudly instead.
*/
function dayCell(iso: string): HTMLButtonElement {
const el = document.querySelector<HTMLButtonElement>(`[data-iso="${iso}"]`);
expect(el, `no day cell rendered for ${iso}`).not.toBeNull();
return el!;
}

describe("Calendar (smoke)", () => {
it("selects a day in single mode", async () => {
const user = userEvent.setup();
const user = setupUser();
const onValueChange = vi.fn();

render(
Expand All @@ -19,16 +49,12 @@ describe("Calendar (smoke)", () => {
// Caption shows month; grid is present
expect(screen.getByRole("grid")).toBeInTheDocument();

const day = document.querySelector<HTMLButtonElement>(
'[data-iso="2026-07-20"]',
);
expect(day).toBeTruthy();
await user.click(day!);
await user.click(dayCell("2026-07-20"));
expect(onValueChange).toHaveBeenCalledWith("2026-07-20");
});

it("supports range start then end", async () => {
const user = userEvent.setup();
const user = setupUser();
const onRangeValueChange = vi.fn();

render(
Expand All @@ -40,13 +66,41 @@ describe("Calendar (smoke)", () => {
/>,
);

await user.click(document.querySelector('[data-iso="2026-07-10"]')!);
await user.click(dayCell("2026-07-10"));
expect(onRangeValueChange).not.toHaveBeenCalled();

await user.click(document.querySelector('[data-iso="2026-07-12"]')!);
await user.click(dayCell("2026-07-12"));
expect(onRangeValueChange).toHaveBeenCalledWith({
start: "2026-07-10",
end: "2026-07-12",
});
});

it("orders a range picked end-first", async () => {
const user = setupUser();
const onRangeValueChange = vi.fn();

render(
<Calendar
mode="range"
defaultRangeValue={{ start: "", end: "" }}
onRangeValueChange={onRangeValueChange}
/>,
);

await user.click(dayCell("2026-07-20"));
await user.click(dayCell("2026-07-14"));

expect(onRangeValueChange).toHaveBeenCalledWith({
start: "2026-07-14",
end: "2026-07-20",
});
});

it("opens on the current month when no value is given", () => {
render(<Calendar aria-label="Pick day" />);

expect(dayCell("2026-07-15")).toHaveAttribute("aria-current", "date");
expect(dayCell("2026-07-31")).toBeInTheDocument();
});
});
Loading