|
| 1 | +import { act, cleanup, fireEvent, render, screen } from "@testing-library/react"; |
| 2 | +import { StrictMode, useState } from "react"; |
| 3 | +import { afterEach, beforeEach, describe, expect, test } from "vitest"; |
| 4 | +import { Dialog } from "./Dialog"; |
| 5 | + |
| 6 | +// jsdom runs no animations; a stand-in says this one does. |
| 7 | +const proto = HTMLElement.prototype as { getAnimations?: () => Animation[] }; |
| 8 | +beforeEach(() => { |
| 9 | + proto.getAnimations = () => []; |
| 10 | +}); |
| 11 | +afterEach(() => { |
| 12 | + cleanup(); |
| 13 | + delete proto.getAnimations; |
| 14 | + for (const copy of document.querySelectorAll(".dialog-exit")) { |
| 15 | + copy.remove(); |
| 16 | + } |
| 17 | +}); |
| 18 | + |
| 19 | +function Owner() { |
| 20 | + const [open, setOpen] = useState(true); |
| 21 | + return open ? ( |
| 22 | + <Dialog title="Edit Scout" onClose={() => setOpen(false)}> |
| 23 | + <input aria-label="Name" defaultValue="Scout" /> |
| 24 | + </Dialog> |
| 25 | + ) : null; |
| 26 | +} |
| 27 | + |
| 28 | +const settle = () => act(() => Promise.resolve()); |
| 29 | + |
| 30 | +describe("dialog motion", () => { |
| 31 | + test("closing leaves a still copy that fades out, then goes", async () => { |
| 32 | + render(<Owner />); |
| 33 | + fireEvent.change(screen.getByRole("textbox", { name: "Name" }), { |
| 34 | + target: { value: "Scout 2" }, |
| 35 | + }); |
| 36 | + fireEvent.click(screen.getByRole("button", { name: "Close" })); |
| 37 | + await settle(); |
| 38 | + expect(screen.queryByRole("dialog")).toBeNull(); |
| 39 | + const copy = document.querySelector(".dialog-exit") as HTMLElement; |
| 40 | + expect(copy.getAttribute("aria-hidden")).toBe("true"); |
| 41 | + expect(copy.inert).toBe(true); |
| 42 | + // What the owner typed stays while it fades. |
| 43 | + expect(copy.querySelector("input")?.value).toBe("Scout 2"); |
| 44 | + const end = new Event("animationend"); |
| 45 | + fireEvent(copy, end); |
| 46 | + expect(document.querySelector(".dialog-exit")).toBeNull(); |
| 47 | + }); |
| 48 | + |
| 49 | + test("being mounted again in strict mode leaves no copy", async () => { |
| 50 | + render( |
| 51 | + <StrictMode> |
| 52 | + <Owner /> |
| 53 | + </StrictMode>, |
| 54 | + ); |
| 55 | + await settle(); |
| 56 | + expect(screen.getByRole("dialog")).toBeDefined(); |
| 57 | + expect(document.querySelector(".dialog-exit")).toBeNull(); |
| 58 | + }); |
| 59 | +}); |
0 commit comments