Skip to content

Commit da71c2f

Browse files
Add tests for calendar and time edge cases
1 parent abe82b6 commit da71c2f

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed

src/test/calendar_test.test.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,58 @@ describe("Calendar", () => {
221221
expect(isSameDay(instance?.state.date, openToDate)).toBeTruthy();
222222
});
223223

224+
it("should move pre-selection to first enabled day when month changes", () => {
225+
const onSelect = jest.fn();
226+
const setOpen = jest.fn();
227+
const setPreSelection = jest.fn();
228+
const filterDate = (date: Date) => date.getDate() >= 3;
229+
230+
const { instance } = getCalendar({
231+
adjustDateOnChange: true,
232+
onSelect,
233+
setOpen,
234+
setPreSelection,
235+
filterDate,
236+
selected: new Date("2024-01-15T00:00:00"),
237+
});
238+
239+
const targetMonth = new Date("2024-02-01T00:00:00");
240+
act(() => {
241+
instance?.handleMonthChange(targetMonth);
242+
});
243+
244+
const expectedDate = new Date("2024-02-03T00:00:00");
245+
const [selectedDate] = onSelect.mock.calls[0];
246+
expect(isSameDay(selectedDate, expectedDate)).toBe(true);
247+
expect(setOpen).toHaveBeenCalledWith(true);
248+
const [preSelectionDate] = setPreSelection.mock.calls[0];
249+
expect(isSameDay(preSelectionDate, expectedDate)).toBe(true);
250+
expect(instance?.state.isRenderAriaLiveMessage).toBe(true);
251+
});
252+
253+
it("should fall back to provided month date when no enabled days exist", () => {
254+
const onSelect = jest.fn();
255+
const setPreSelection = jest.fn();
256+
const filterDate = () => false;
257+
258+
const { instance } = getCalendar({
259+
adjustDateOnChange: true,
260+
onSelect,
261+
setPreSelection,
262+
filterDate,
263+
});
264+
265+
const targetDate = new Date("2024-03-10T00:00:00");
266+
act(() => {
267+
instance?.handleMonthChange(targetDate);
268+
});
269+
270+
const [fallbackSelected] = onSelect.mock.calls[0];
271+
expect(isSameDay(fallbackSelected, targetDate)).toBe(true);
272+
const [fallbackPreSelection] = setPreSelection.mock.calls[0];
273+
expect(isSameDay(fallbackPreSelection, targetDate)).toBe(true);
274+
});
275+
224276
it("should open on openToDate date rather than selected date when both are specified", () => {
225277
const openToDate =
226278
parseDate("09/28/1993", DATE_FORMAT, undefined, false) ?? undefined;

src/test/click_outside_wrapper.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,34 @@ describe("ClickOutsideWrapper", () => {
148148
expect(containerRef.current?.tagName).toBe("DIV");
149149
});
150150

151+
it("handles composedPath events (e.g. shadow DOM)", () => {
152+
render(
153+
<div>
154+
<ClickOutsideWrapper onClickOutside={onClickOutsideMock}>
155+
<div data-testid="inside">Inside</div>
156+
</ClickOutsideWrapper>
157+
</div>,
158+
);
159+
160+
const outsideNode = document.createElement("div");
161+
document.body.appendChild(outsideNode);
162+
163+
const event = new MouseEvent("mousedown", {
164+
bubbles: true,
165+
composed: true,
166+
});
167+
Object.defineProperty(event, "composed", { value: true });
168+
Object.defineProperty(event, "composedPath", {
169+
value: () => [outsideNode, document.body],
170+
});
171+
172+
outsideNode.dispatchEvent(event);
173+
174+
expect(onClickOutsideMock).toHaveBeenCalled();
175+
176+
document.body.removeChild(outsideNode);
177+
});
178+
151179
it("cleans up event listener on unmount", () => {
152180
const removeEventListenerSpy = jest.spyOn(document, "removeEventListener");
153181

src/test/filter_times_test.test.tsx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render } from "@testing-library/react";
1+
import { fireEvent, render } from "@testing-library/react";
22
import React from "react";
33

44
import { getHours } from "../date_utils";
@@ -50,4 +50,42 @@ describe("TimeComponent", () => {
5050
).every((time) => time.getAttribute("aria-disabled") === "true");
5151
expect(allDisabledTimeItemsHaveAriaDisabled).toBe(true);
5252
});
53+
54+
it("should block onChange for disabled times", () => {
55+
const onChange = jest.fn();
56+
const { container } = render(
57+
<TimeComponent
58+
onChange={onChange}
59+
filterTime={(time) => getHours(time) !== HOUR_TO_DISABLE_IN_24_HR}
60+
/>,
61+
);
62+
63+
const disabledTime = Array.from(
64+
container.querySelectorAll(".react-datepicker__time-list-item"),
65+
).find((node) =>
66+
node.classList.contains("react-datepicker__time-list-item--disabled"),
67+
) as HTMLElement;
68+
69+
fireEvent.click(disabledTime);
70+
71+
expect(onChange).not.toHaveBeenCalled();
72+
});
73+
74+
it("should call onChange for enabled times", () => {
75+
const onChange = jest.fn();
76+
const { container } = render(
77+
<TimeComponent onChange={onChange} filterTime={() => true} />,
78+
);
79+
80+
const enabledTime = Array.from(
81+
container.querySelectorAll(".react-datepicker__time-list-item"),
82+
).find(
83+
(node) =>
84+
!node.classList.contains("react-datepicker__time-list-item--disabled"),
85+
) as HTMLElement;
86+
87+
fireEvent.click(enabledTime);
88+
89+
expect(onChange).toHaveBeenCalled();
90+
});
5391
});

0 commit comments

Comments
 (0)