From e0ca80d98ab28d7b96bc8cce404e106ea270ed19 Mon Sep 17 00:00:00 2001 From: Arda Demir Date: Wed, 5 Aug 2026 17:37:40 +0300 Subject: [PATCH] test(ui): pin the Calendar clock so range specs stop depending on today The range specs clicked hardcoded July 2026 cells, but in range mode the opening view is derived from `defaultRangeValue`, and an empty range falls back to today. Those cells only render while the clock sits in July 2026, so the suite went red on 1 August with no source change. user-event no-ops on a null target instead of throwing, so the missing cells also made `expect(onRangeValueChange).not.toHaveBeenCalled()` pass vacuously and pushed the failure one assertion further down. - freeze the clock at 2026-07-15 for this file - route every click through `dayCell()`, which fails when a cell is absent - add coverage for end-first range ordering and the default month view Verified green with the real clock frozen to January, April, August and December. Co-Authored-By: Claude Opus 5 (1M context) --- packages/ui/src/atoms/calendar.test.tsx | 74 +++++++++++++++++++++---- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/atoms/calendar.test.tsx b/packages/ui/src/atoms/calendar.test.tsx index 6bae5c9..80a215b 100644 --- a/packages/ui/src/atoms/calendar.test.tsx +++ b/packages/ui/src/atoms/calendar.test.tsx @@ -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(`[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( @@ -19,16 +49,12 @@ describe("Calendar (smoke)", () => { // Caption shows month; grid is present expect(screen.getByRole("grid")).toBeInTheDocument(); - const day = document.querySelector( - '[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( @@ -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( + , + ); + + 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(); + + expect(dayCell("2026-07-15")).toHaveAttribute("aria-current", "date"); + expect(dayCell("2026-07-31")).toBeInTheDocument(); + }); });