// @vitest-environment happy-dom import { afterEach, describe, expect, it, vi } from "vitest"; import { closeContextMenu, openContextMenu } from "./contextMenu.js"; afterEach(() => { closeContextMenu(); document.body.replaceChildren(); }); function labels(): string[] { return [...document.querySelectorAll(".context-menu-item")].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(document.querySelector(".context-menu-item.is-danger")?.textContent).toBe( "Kill session", ); }); it("runs the selected entry and closes", () => { const chosen = vi.fn(); openContextMenu(0, 0, [{ label: "Rename…", onSelect: chosen }]); (document.querySelector(".context-menu-item") as HTMLButtonElement).click(); expect(chosen).toHaveBeenCalledOnce(); expect(document.querySelector(".context-menu")).toBeNull(); }); it("opening a second menu replaces the first", () => { openContextMenu(0, 0, [{ label: "first", onSelect: () => {} }]); openContextMenu(0, 0, [{ label: "second", onSelect: () => {} }]); expect(document.querySelectorAll(".context-menu")).toHaveLength(1); expect(labels()).toEqual(["second"]); }); it("closes on Escape and on a press outside it", () => { openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); window.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" })); expect(document.querySelector(".context-menu")).toBeNull(); openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); document.body.dispatchEvent(new Event("pointerdown", { bubbles: true })); expect(document.querySelector(".context-menu")).toBeNull(); }); it("stays open for a press inside itself", () => { openContextMenu(0, 0, [{ label: "Rename…", onSelect: () => {} }]); const menu = document.querySelector(".context-menu") as HTMLElement; menu.dispatchEvent(new Event("pointerdown", { bubbles: true })); expect(document.querySelector(".context-menu")).not.toBeNull(); }); });