Files
WRNexusJS/packages/ui/test/calendar-layout.test.ts

80 lines
3.6 KiB
TypeScript

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);
});