/** * @file clipboard.test.ts * @description `writeClipboard` / `copyText`: the async Clipboard API when the * origin has one, else the hidden-textarea `execCommand("copy")` — the only * path on `http://`, where a terminal selection must still reach the * user's clipboard — and the focus goes back to where it was. * @author Nguyễn Ngọc Trí Vĩ */ import { afterEach, describe, expect, it, vi } from "vitest"; import { copyText, writeClipboard } from "../clipboard"; const original = Object.getOwnPropertyDescriptor(navigator, "clipboard"); const setClipboard = (value: unknown) => Object.defineProperty(navigator, "clipboard", { value, configurable: true }); afterEach(() => { if (original) Object.defineProperty(navigator, "clipboard", original); else delete (navigator as { clipboard?: unknown }).clipboard; vi.restoreAllMocks(); }); describe("writeClipboard", () => { it("uses the Clipboard API when the origin has one", async () => { const writeText = vi.fn().mockResolvedValue(undefined); setClipboard({ writeText }); expect(await writeClipboard("hello")).toBe(true); expect(writeText).toHaveBeenCalledWith("hello"); }); it("falls back to execCommand on a non-secure origin, and gives the focus back", async () => { setClipboard(undefined); const input = document.createElement("input"); document.body.appendChild(input); input.focus(); let copied = ""; const exec = vi.fn((cmd: string) => { copied = document.querySelector("textarea")?.value ?? ""; return cmd === "copy"; }); Object.defineProperty(document, "execCommand", { value: exec, configurable: true }); expect(await writeClipboard("from tmux")).toBe(true); expect(exec).toHaveBeenCalledWith("copy"); expect(copied).toBe("from tmux"); expect(document.activeElement).toBe(input); expect(document.querySelector("textarea")).toBeNull(); input.remove(); }); it("copyText reports a failed copy", async () => { setClipboard(undefined); Object.defineProperty(document, "execCommand", { value: vi.fn(() => false), configurable: true, }); expect(await copyText("x", true)).toBe(false); }); });