Files
skills/docs/testkit/testing/testing-e2e/src/helpers/mock-clipboard.md
2026-05-29 08:20:56 +01:00

2.8 KiB

mock-clipboard

Purpose

mockClipboard installs a deterministic, in-memory clipboard implementation on the navigator object for a Playwright page. The default clipboard shipped by Chromium headless requires explicit user-gesture permissions and does not work at all in some CI environments; this helper replaces it with a programmatic pair of writeText / readText that behaves identically in every environment.

Features

  • Installs via page.addInitScript so the mock is active before any app code runs
  • In-memory state is per-page — different pages don't share clipboard state
  • Matches the real navigator.clipboard API surface for writeText and readText
  • Idempotent — calling twice on the same page just re-installs the same script

Usage: Basic Example

import { mockClipboard } from "@suaveplan/testing-e2e/helpers";

await mockClipboard(page);
await page.goto("/settings");
await page.click("text=Copy API key");
const copied = await page.evaluate(() => navigator.clipboard.readText());
expect(copied).toMatch(/^sk_/);

Usage: Advanced Example

import { mockClipboard } from "@suaveplan/testing-e2e/helpers";
import { expect } from "@playwright/test";

test("copy + paste round trip", async ({ page }) => {
    await mockClipboard(page);
    await page.goto("/notes/123");

    await page.getByRole("button", { name: /copy link/i }).click();
    const copied = await page.evaluate(() => navigator.clipboard.readText());
    expect(copied).toBe("https://notes.example/123");

    // Paste somewhere:
    await page.goto("/notes/new");
    await page.evaluate(async () => {
        const text = await navigator.clipboard.readText();
        (document.querySelector("textarea") as HTMLTextAreaElement).value = text;
    });
    await expect(page.locator("textarea")).toHaveValue("https://notes.example/123");
});

API Reference

mockClipboard(page): Promise<void>

  • page: Page — Playwright page (must be called before any navigation for the init script to take effect)
  • Returns Promise<void> that resolves after the init script is registered

Implementation Notes

The init script defines navigator.clipboard using Object.defineProperty with writable: true so a test that wants to swap in a further spy can still do so. Because the mock is installed via addInitScript, it's reinstalled automatically on every navigation within the same page — tests don't need to reinstall after page.goto.

Behaviour

mockClipboard(page) installs an addInitScript that replaces navigator.clipboard.readText / writeText with in-memory stubs whose state survives page navigations inside the same context. A companion getClipboardValue(page) reads the current mock value synchronously from the page's JS context so assertions do not need to await a clipboard-permissions prompt.