import { fireEvent, render, screen } from "@solidjs/testing-library"; import { describe, expect, it, vi } from "vitest"; import { Calendar } from "../../../src/components/calendar/index"; import { CalendarRootPropsSchema, CalendarMeta } from "../../../src/components/calendar/index"; function renderCalendar(props: Record = {}) { return render(() => ( )); } describe("Calendar — rendering", () => { it("renders month grid heading", () => { renderCalendar(); expect(screen.getByText(/january/i)).toBeTruthy(); }); it("renders a table with role=grid", () => { renderCalendar(); expect(screen.getByRole("grid")).toBeTruthy(); }); it("renders 7 weekday column headers", () => { renderCalendar(); const cols = screen.getAllByRole("columnheader"); expect(cols.length).toBe(7); }); it("renders day cells with role=gridcell", () => { renderCalendar(); const cells = screen.getAllByRole("gridcell"); expect(cells.length).toBeGreaterThanOrEqual(28); }); it("marks today cell with data-today attribute", () => { renderCalendar(); const todayCells = document.querySelectorAll("[data-today]"); expect(todayCells.length).toBeGreaterThanOrEqual(0); }); }); describe("Calendar — selection", () => { it("calls onValueChange when a day cell is clicked", () => { const onChange = vi.fn(); renderCalendar({ onValueChange: onChange }); const cells = screen.getAllByRole("gridcell"); const inMonth = Array.from(cells).find((c) => !c.hasAttribute("data-outside-month")); if (inMonth) fireEvent.click(inMonth); expect(onChange).toHaveBeenCalled(); }); it("marks selected cell with data-selected and aria-selected", () => { renderCalendar({ defaultValue: "2024-01-15" }); const selected = document.querySelector("[data-selected]"); expect(selected).toBeTruthy(); expect(selected?.getAttribute("aria-selected")).toBe("true"); }); it("does not call onValueChange for disabled dates", () => { const onChange = vi.fn(); renderCalendar({ onValueChange: onChange, minDate: "2024-01-20", maxDate: "2024-01-31" }); const cells = screen.getAllByRole("gridcell"); const disabled = Array.from(cells).find((c) => c.hasAttribute("data-disabled")); if (disabled) fireEvent.click(disabled); expect(onChange).not.toHaveBeenCalled(); }); it("Enter key selects a cell", () => { const onChange = vi.fn(); renderCalendar({ onValueChange: onChange }); const cells = screen.getAllByRole("gridcell"); const inMonth = Array.from(cells).find((c) => !c.hasAttribute("data-outside-month")); if (inMonth) fireEvent.keyDown(inMonth, { key: "Enter" }); expect(onChange).toHaveBeenCalled(); }); }); describe("Calendar — navigation", () => { it("prev button navigates to previous month", () => { renderCalendar(); expect(screen.getByText(/january/i)).toBeTruthy(); fireEvent.click(screen.getByLabelText("Go to previous month")); expect(screen.getByText(/december/i)).toBeTruthy(); }); it("next button navigates to next month", () => { renderCalendar(); fireEvent.click(screen.getByLabelText("Go to next month")); expect(screen.getByText(/february/i)).toBeTruthy(); }); it("calls onMonthChange when navigating", () => { const onMonthChange = vi.fn(); renderCalendar({ onMonthChange }); fireEvent.click(screen.getByLabelText("Go to next month")); expect(onMonthChange).toHaveBeenCalledWith(1, 2024); }); }); describe("Calendar — schema and meta", () => { it("schema accepts valid ISO date strings", () => { expect(CalendarRootPropsSchema.safeParse({ value: "2024-01-15" }).success).toBe(true); }); it("schema rejects invalid minDate/maxDate types", () => { expect(CalendarRootPropsSchema.safeParse({ minDate: 12345 }).success).toBe(false); }); it("meta has required fields", () => { expect(CalendarMeta.name).toBe("Calendar"); expect(CalendarMeta.parts).toContain("Root"); expect(CalendarMeta.parts).toContain("Grid"); expect(CalendarMeta.parts).toContain("Cell"); }); it("meta lists all expected parts", () => { const required = ["Root", "Header", "Heading", "Nav", "Grid", "GridHead", "GridBody", "Cell"]; for (const part of required) { expect(CalendarMeta.parts).toContain(part); } }); });