import React from "react"; import { noop } from "lodash"; import { render, screen, fireEvent, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Modal from "./Modal"; const clickBackground = async (background: Element | null) => { if (!background) throw new Error("Background element not found"); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); await user.pointer([ { keys: "[MouseLeft>]", target: background }, { keys: "[/MouseLeft]", target: background }, ]); }; describe("Modal", () => { beforeEach(() => jest.useFakeTimers()); afterEach(() => jest.useRealTimers()); it("renders title", () => { render(
test
); expect(screen.getByText("Foobar")).toBeVisible(); }); it("calls onExit when clicking the background overlay", async () => { const onExit = jest.fn(); const { container } = render(
content
); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).toHaveBeenCalledTimes(1); }); it("does not call onExit when clicking inside the modal container", () => { const onExit = jest.fn(); const { container } = render(
content
); // Simulate drag that starts inside the container and releases on the background. // The container stops mouseDown propagation so isDownOnBackgroundRef stays false, // meaning the background's mouseUp handler must not fire onExit. fireEvent.mouseDown(screen.getByText("content")); const background = container.querySelector(".modal__background"); if (!background) throw new Error("Background element not found"); fireEvent.mouseUp(background); expect(onExit).not.toHaveBeenCalled(); }); it("does not call onExit when clicking the background if a form inside has been interacted with", async () => { const onExit = jest.fn(); const { container } = render(
); const input = screen.getByRole("textbox"); fireEvent.input(input, { target: { value: "hello" } }); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).not.toHaveBeenCalled(); }); it("does not call onExit when clicking the background if a text input outside a form has been interacted with", async () => { const onExit = jest.fn(); const { container } = render(
); const input = screen.getByRole("textbox"); fireEvent.input(input, { target: { value: "hello" } }); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).not.toHaveBeenCalled(); }); it("does not call onExit when clicking the background if a checkbox has been checked", async () => { const onExit = jest.fn(); const { container } = render(
); const checkbox = screen.getByRole("checkbox"); fireEvent.click(checkbox); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).not.toHaveBeenCalled(); }); it("does not call onExit when clicking the background if a toggle has been clicked", async () => { const onExit = jest.fn(); const { container } = render(
); const toggle = screen.getByRole("switch"); fireEvent.click(toggle); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).not.toHaveBeenCalled(); }); it("calls onExit when clicking the background if a form inside has not been interacted with", async () => { const onExit = jest.fn(); const { container } = render(
); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).toHaveBeenCalledTimes(1); }); it("does not call onExit when clicking the background if disableClosingModal is true", async () => { const onExit = jest.fn(); const { container } = render(
content
); const background = container.querySelector(".modal__background"); await clickBackground(background); act(() => jest.runAllTimers()); expect(onExit).not.toHaveBeenCalled(); }); });