import { expect, test } from "bun:test"; import { readFileSync } from "node:fs"; import { mountHtml, renderComponent } from "../../test/src/index.ts"; import { uiComponentPath } from "../src/registry.ts"; const source = readFileSync(uiComponentPath("DatePicker"), "utf8"); test("calendar aligns leap February with Monday-first labels and disables out-of-range dates", async () => { const dom = mountHtml( await renderComponent(source, { value: "2024-02-15", firstDayOfWeek: 1, min: "2024-02-10", max: "2024-02-20", }), ); const days = dom.querySelectorAll(".wrn-next__calendar-grid button") as HTMLButtonElement[]; expect(days).toHaveLength(29); expect(days[0].style.gridColumn).toBe("4"); expect(dom.querySelector(".wrn-next__calendar-weekdays")?.textContent).toContain("Mon"); expect(days[8].disabled).toBe(true); expect(days[9].disabled).toBe(false); expect(days[20].disabled).toBe(true); expect(days[14].getAttribute("aria-pressed")).toBe("true"); expect(days[14].getAttribute("aria-label")).toContain("February"); }); test("calendar starts from an empty value, selects a date, and returns focus on Escape", async () => { const dom = mountHtml(await renderComponent(source, { name: "date", value: "" })); const trigger = dom.querySelector(".wrn-next__date-trigger") as HTMLButtonElement; trigger.click(); const days = dom.querySelectorAll(".wrn-next__calendar-grid button") as HTMLButtonElement[]; days[0].click(); expect((dom.querySelector("input") as HTMLInputElement).value).toMatch(/^\d{4}-\d{2}-01$/); const selected = dom.querySelector('button[aria-pressed="true"]') as HTMLButtonElement; selected.focus(); selected.dispatchEvent( new (dom.window as Window & typeof globalThis).KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true, }), ); expect((dom.document.activeElement as HTMLElement)?.textContent).toBe("2"); dom.document.activeElement!.dispatchEvent( new (dom.window as Window & typeof globalThis).KeyboardEvent("keydown", { key: "Escape", bubbles: true, }), ); expect(trigger.getAttribute("aria-expanded")).toBe("false"); expect(dom.document.activeElement).toBe(trigger); }); test("calendar has 28 days in a non-leap February and cannot select while read-only", async () => { const dom = mountHtml(await renderComponent(source, { value: "2025-02-15", readonly: true })); const days = dom.querySelectorAll(".wrn-next__calendar-grid button") as HTMLButtonElement[]; expect(days).toHaveLength(28); expect(Array.from(days).every((day) => day.disabled)).toBe(true); days[0].click(); expect((dom.querySelector("input") as HTMLInputElement).value).toBe("2025-02-15"); }); test("calendar keeps native month and year controls aligned after opening and changing months", async () => { const dom = mountHtml(await renderComponent(source, { value: "2026-09-20" })); (dom.querySelector(".wrn-next__date-trigger") as HTMLButtonElement).click(); await new Promise((resolve) => setTimeout(resolve, 10)); let selectors = dom.querySelectorAll(".wrn-next__date-selectors select") as HTMLSelectElement[]; expect(selectors[0].value).toBe("09"); expect(selectors[1].value).toBe("2026"); selectors[0].value = "02"; selectors[0].dispatchEvent( new (dom.window as Window & typeof globalThis).Event("change", { bubbles: true }), ); await new Promise((resolve) => setTimeout(resolve, 10)); selectors = dom.querySelectorAll(".wrn-next__date-selectors select") as HTMLSelectElement[]; expect(selectors[0].value).toBe("02"); expect(selectors[1].value).toBe("2026"); expect(dom.querySelectorAll(".wrn-next__calendar-grid button")).toHaveLength(28); });