I have a DatePicker component like this:
const MonthPanel = ({ setMode = () => {} }) => {
return (
<div>
<button
onClick={(e) => setMode("year")}
data-testid="datepicker-year-button"
>
2021
</button>
</div>
);
};
const YearPanel = () => {
return <div data-testid="datepicker-year-panel">YearPanel</div>;
};
const DatePicker = (props) => {
const [open, setOpen] = useState(false);
const [mode, setMode] = useState("month");
const containerRef = useRef();
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const handleModeChange = (newMode) => {
setMode(newMode);
};
const generatePanel = () => {
switch (mode) {
case "month":
return <MonthPanel setMode={handleModeChange} />;
case "year":
return <YearPanel />;
default:
return null;
}
};
useEffect(() => {
const handleOutsideClick = (e) => {
if (containerRef.current && !containerRef.current.contains(e.target)) {
handleClose();
}
};
window.addEventListener("click", handleOutsideClick);
return () => {
window.removeEventListener("click", handleOutsideClick);
};
}, []);
return (
<div
ref={containerRef}
data-testid="datepicker-container"
>
<div onClick={handleOpen} data-testid="datepicker-input">
Select a date
</div>
{open && <div data-testid="datepicker-dialog">{generatePanel()}</div>}
</div>
);
};
And I have a test file like this:
it.only("should close DatePicker dialog when clicked only outside DatePicker", () => {
const { getByTestId, queryByTestId } = render(
<DatePicker />
);
userEvent.click(getByTestId("datepicker-input"));
userEvent.click(getByTestId("datepicker-year-button"));
expect(queryByTestId("datepicker-dialog")).toBeInTheDocument();
userEvent.click(document.body);
expect(queryByTestId("datepicker-dialog")).toBeNull();
});
Desired state:
When you click outside DatePicker, it should close. And when you click [data-testid="datepicker-year-button"] it should change DatePicker mode to "year", so the year panel will be shown.
Current state:
When you click [data-testid="datepicker-year-button"], it changes Datepicker mode to "year" and MonthPanel (and with it button itself) are removed. Because the button is event target and has already removed, containerRef.current.contains(e.target) condition is false and Dialog will be removed too. But the test is showing that dialog is in the document.
The question is how I should test this functionality correctly.
from React test passes but component does not work properly when state updated in document.addListener handler
No comments:
Post a Comment