// @vitest-environment happy-dom import { afterEach, describe, expect, it, vi } from "vitest"; import { fireEvent, screen } from "@testing-library/react"; import "@testing-library/jest-dom/vitest"; import { closeContextMenu, openContextMenu } from "./contextMenu.js"; afterEach(() => { closeContextMenu(); document.body.replaceChildren(); }); function labels(): string[] { return screen.getAllByRole("menuitem").map((b) => b.textContent ?? ""); } describe("context menu (#125)", () => { it("renders one item per entry, in order", () => { openContextMenu(10, 20, [ { label: "Rename…", onSelect: () => {} }, { label: "Kill session", onSelect: () => {}, danger: true }, ]); expect(labels()).toEqual(["Rename…", "Kill session"]); expect(screen.getByRole("menuitem", { name: "Kill session" })).toHaveClass("is-danger"); }); it("runs the selected entry and closes", () => { const chosen = vi.fn(); openContextMenu(0, 0, [{ label: "Rename…", onSelect: chosen }]); fireEvent.click(screen.getByRole("menuitem", { name: "Rename…" })); expect(chosen).toHaveBeenCalledOnce(); expect(screen.queryByRole("menu")).toBeNull(); }); it("opening a second menu replaces the first", () => { openContextMenu(0, 0, [{ label: "first", onSelect: () => {} }]); openContextMenu(0, 0, [{ label: "second", onSelect: () => {} }]); expect(screen.getAllByRole("menu")).toHaveLength(1); expect(labels()).toEqual(["second"]); }); it("closes on Escape and on a press outside it", () => { openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); fireEvent.keyDown(window, { key: "Escape" }); expect(screen.queryByRole("menu")).toBeNull(); openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); fireEvent.pointerDown(document.body); expect(screen.queryByRole("menu")).toBeNull(); }); it("stays open for a press inside itself", () => { openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); const menu = screen.getByRole("menu"); fireEvent.pointerDown(menu); expect(screen.queryByRole("menu")).not.toBeNull(); }); });