import { afterEach, describe, expect, it, vi } from "vitest"; import { copyMenuFor, copyText, selectableText } from "./selectableText"; function mount(html: string) { document.body.innerHTML = html; return document.body; } function select(node: Node) { const range = document.createRange(); range.selectNodeContents(node); const sel = window.getSelection()!; sel.removeAllRanges(); sel.addRange(range); } afterEach(() => { window.getSelection()?.removeAllRanges(); document.body.innerHTML = ""; vi.restoreAllMocks(); }); describe("selectableText", () => { it("is a real class name", () => { expect(selectableText).toBeTruthy(); }); }); describe("copyMenuFor", () => { it("offers Copy of the selection in a selectable pane (issue #36: Markdown preview)", () => { mount(`

Hello world

`); select(document.getElementById("p")!); const items = copyMenuFor(document.getElementById("b")); expect(items).toHaveLength(1); expect(items![0]).toMatchObject({ label: "Copy", disabled: false }); }); it("offers a disabled Copy in a selectable pane with nothing selected", () => { mount(`

Hello

`); expect(copyMenuFor(document.getElementById("p"))![0]).toMatchObject({ label: "Copy", disabled: true }); }); it("resolves text-node targets", () => { mount(`

Hello

`); expect(copyMenuFor(document.getElementById("p")!.firstChild)).not.toBeNull(); }); it("offers Copy on a selection in any pane that opted in with its own CSS", () => { mount(`
line 1
`); select(document.getElementById("console")!); expect(copyMenuFor(document.getElementById("console"))![0]).toMatchObject({ disabled: false }); }); it("stays out of chrome without a selection", () => { mount(`
tree row
`); expect(copyMenuFor(document.getElementById("b"))).toBeNull(); expect(copyMenuFor(document.getElementById("row"))).toBeNull(); }); it("ignores a selection elsewhere when right-clicking chrome", () => { mount(`

Hello

tree row
`); select(document.getElementById("p")!); expect(copyMenuFor(document.getElementById("row"))).toBeNull(); }); it.each(["", "", "
x
"])( "leaves editable targets alone: %s", (html) => { mount(`
${html}
`); expect(copyMenuFor(document.getElementById("t"))).toBeNull(); }, ); it("copies the text captured when the menu opened", async () => { const writeText = vi.fn().mockResolvedValue(undefined); Object.defineProperty(navigator, "clipboard", { value: { writeText }, configurable: true }); mount(`

Hello

`); select(document.getElementById("p")!); const items = copyMenuFor(document.getElementById("p"))!; window.getSelection()!.removeAllRanges(); (items[0] as { run: () => void }).run(); await Promise.resolve(); expect(writeText).toHaveBeenCalledWith("Hello"); }); it("falls back to execCommand when the clipboard API is missing", async () => { Object.defineProperty(navigator, "clipboard", { value: undefined, configurable: true }); const exec = vi.fn().mockReturnValue(true); document.execCommand = exec; await copyText("x"); expect(exec).toHaveBeenCalledWith("copy"); }); });