fleet/frontend/components/Modal/Modal.tests.tsx

171 lines
5.3 KiB
TypeScript
Raw Normal View History

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(
<Modal title="Foobar" onExit={noop}>
<div>test</div>
</Modal>
);
expect(screen.getByText("Foobar")).toBeVisible();
});
it("calls onExit when clicking the background overlay", async () => {
const onExit = jest.fn();
const { container } = render(
<Modal title="Test" onExit={onExit}>
<div>content</div>
</Modal>
);
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(
<Modal title="Test" onExit={onExit}>
<div>content</div>
</Modal>
);
// 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(
<Modal title="Test" onExit={onExit}>
<form>
<input type="text" />
</form>
</Modal>
);
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(
<Modal title="Test" onExit={onExit}>
<div>
<input type="text" />
</div>
</Modal>
);
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(
<Modal title="Test" onExit={onExit}>
<div>
<input type="checkbox" />
</div>
</Modal>
);
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(
<Modal title="Test" onExit={onExit}>
<div>
<button type="button" role="switch" aria-checked={false}>
Toggle
</button>
</div>
</Modal>
);
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(
<Modal title="Test" onExit={onExit}>
<form>
<input type="text" />
</form>
</Modal>
);
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(
<Modal title="Test" onExit={onExit} disableClosingModal>
<div>content</div>
</Modal>
);
const background = container.querySelector(".modal__background");
await clickBackground(background);
act(() => jest.runAllTimers());
expect(onExit).not.toHaveBeenCalled();
});
});