import { render, fireEvent } from "@testing-library/react";
import React from "react";
import InputTime from "../input_time";
import CustomTimeInput from "./helper_components/custom_time_input";
describe("InputTime", () => {
it("renders with default props", () => {
const { container } = render();
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
expect(timeInput).toBeTruthy();
expect(timeInput.className).toBe("react-datepicker-time__input");
expect(timeInput.placeholder).toBe("Time");
});
it("renders with timeString prop", () => {
const { container } = render();
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
expect(timeInput.value).toBe("14:30");
});
it("renders with timeInputLabel prop", () => {
const { container } = render();
const label = container.querySelector(
".react-datepicker-time__caption",
) as HTMLElement;
expect(label.textContent).toBe("Select Time");
});
it("calls onChange when time is changed", () => {
const onChangeMock = jest.fn();
const { container } = render(
,
);
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
fireEvent.change(timeInput, { target: { value: "15:45" } });
expect(onChangeMock).toHaveBeenCalledTimes(1);
const calledDate = onChangeMock.mock.calls[0][0];
expect(calledDate.getHours()).toBe(15);
expect(calledDate.getMinutes()).toBe(45);
});
it("updates state when timeString prop changes", () => {
const { container, rerender } = render();
let timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
expect(timeInput.value).toBe("10:00");
rerender();
timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
expect(timeInput.value).toBe("16:30");
});
it("uses provided date when onChange is called", () => {
const onChangeMock = jest.fn();
const testDate = new Date(2023, 5, 15, 10, 30);
const { container } = render(
,
);
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
fireEvent.change(timeInput, { target: { value: "14:45" } });
expect(onChangeMock).toHaveBeenCalledTimes(1);
const calledDate = onChangeMock.mock.calls[0][0];
expect(calledDate.getFullYear()).toBe(2023);
expect(calledDate.getMonth()).toBe(5);
expect(calledDate.getDate()).toBe(15);
expect(calledDate.getHours()).toBe(14);
expect(calledDate.getMinutes()).toBe(45);
});
it("creates new date when no date prop is provided", () => {
const onChangeMock = jest.fn();
const { container } = render(
,
);
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
fireEvent.change(timeInput, { target: { value: "14:45" } });
expect(onChangeMock).toHaveBeenCalledTimes(1);
const calledDate = onChangeMock.mock.calls[0][0];
expect(calledDate).toBeInstanceOf(Date);
expect(calledDate.getHours()).toBe(14);
expect(calledDate.getMinutes()).toBe(45);
});
it("renders custom time input when provided", () => {
const CustomTimeInput = ({
value,
onChange,
}: {
value: string;
onChange: (time: string) => void;
}) => (
onChange(e.target.value)}
/>
);
const { container } = render(
{}} />}
timeString="12:00"
/>,
);
const customInput = container.querySelector(
'[data-testid="custom-time-input"]',
) as HTMLInputElement;
expect(customInput).toBeTruthy();
expect(customInput.value).toBe("12:00");
});
it("calls onChange with custom time input", () => {
const onChangeMock = jest.fn();
const CustomTimeInput = ({
value,
onChange,
}: {
value: string;
onChange: (time: string) => void;
}) => (
onChange(e.target.value)}
/>
);
const { container } = render(
{}} />}
timeString="12:00"
/>,
);
const customInput = container.querySelector(
'[data-testid="custom-time-input"]',
) as HTMLInputElement;
fireEvent.change(customInput, { target: { value: "18:30" } });
expect(onChangeMock).toHaveBeenCalledTimes(1);
const calledDate = onChangeMock.mock.calls[0][0];
expect(calledDate.getHours()).toBe(18);
expect(calledDate.getMinutes()).toBe(30);
});
it("focuses input when clicked", () => {
const { container } = render();
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
const focusSpy = jest.spyOn(timeInput, "focus");
fireEvent.click(timeInput);
expect(focusSpy).toHaveBeenCalled();
focusSpy.mockRestore();
});
it("uses timeString as fallback when onChange value is empty", () => {
const onChangeMock = jest.fn();
const { container } = render(
,
);
const timeInput = container.querySelector(
'input[type="time"]',
) as HTMLInputElement;
fireEvent.change(timeInput, { target: { value: "" } });
expect(onChangeMock).toHaveBeenCalledTimes(1);
expect(timeInput.value).toBe("10:00");
});
it("passes provided date through customTimeInput onTimeChange handler", () => {
const onTimeChange = jest.fn();
const date = new Date("2023-09-30T10:00:00");
const { container } = render(
}
/>,
);
const customInput = container.querySelector(
'[data-testid="custom-time-input"]',
) as HTMLInputElement;
fireEvent.change(customInput, { target: { value: "11:15" } });
expect(onTimeChange).toHaveBeenCalledWith(date);
});
it("preserves existing time when custom input emits value without colon", () => {
const onChange = jest.fn();
const date = new Date("2023-09-30T11:00:00");
const { container } = render(
}
/>,
);
const customInput = container.querySelector(
'[data-testid="partial-input"]',
) as HTMLInputElement;
fireEvent.change(customInput, { target: { value: "invalid" } });
expect(onChange).toHaveBeenCalledTimes(1);
const calledDate = onChange.mock.calls[0][0];
expect(calledDate.getHours()).toBe(11);
expect(calledDate.getMinutes()).toBe(0);
});
it("renders container with correct class names", () => {
const { container } = render();
expect(
container.querySelector(".react-datepicker__input-time-container"),
).toBeTruthy();
expect(
container.querySelector(".react-datepicker-time__input-container"),
).toBeTruthy();
expect(
container.querySelector(".react-datepicker-time__input"),
).toBeTruthy();
});
});