Files
skills/plugins/document-navigator/docs/testkit/testing/testing-e2e
admin 9bf56a806b Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:10:00 +01:00
..

@suaveplan/testing-e2e - Stealth Playwright E2E utilities backed by cloakbrowser — config factory, page objects, fixtures, helpers, structured errors. Drop-in browser-launch swap that passes Cloudflare Turnstile, reCAPTCHA v3, FingerprintJS. Layer 0; no @suaveplan/* runtime deps

Summary

Playwright E2E testing utilities for Suaveplan, with the default browser worker fixture launching cloakbrowser — a real Chromium binary with 49 source-level C++ fingerprint patches — instead of the stock Playwright Chromium. Every spec that imports extendedTest from this package gets navigator.webdriver === false, real GPU/canvas/audio/screen/WebRTC fingerprints, a normal window.chrome, no HeadlessChrome UA leak, and no CDP detection signal. Cloudflare Turnstile, reCAPTCHA v3 (0.9 score), FingerprintJS, BrowserScan, and ShieldSquare see a normal browser.

The rest of the package is unchanged: a config factory with WSL2/CI defaults, an abstract PageObject base, an apiContext fixture that deliberately does NOT depend on browser, network/console monitors, multi-session orchestration, OTel-instrumented entry points, and a structured TestingE2eError hierarchy (now with CLOAK_* codes). Layer 0 — no @suaveplan/* runtime dependencies.

What the swap changes

  • extendedTest.browser is launched via cloakbrowser.launch. The returned object is still a Playwright Browser from playwright-core — every fixture, page object, helper, and monitor works unchanged.
  • A new worker option cloak: CloakOptions flows into the launcher. Set per project in playwright.config.ts: use: { cloak: { humanize: true, geoip: true, proxy: "…" } }.
  • launchWithExtension defaults to cloakbrowser.launchPersistentContext and exposes a launchPersistentContext injector for tests / profile managers.
  • Failures classify into TESTING_E2E.CLOAK.{LAUNCH_FAILED,BINARY_MISSING,PROXY_INVALID} via classifyCloakError + wrapCloakError, wrapped in CloakLaunchError.
  • @playwright/test stays as the test runner — cloakbrowser is a drop-in browser-launch replacement, not a runner replacement.
  • No public re-exports of cloakbrowser symbols. Per CLAUDE.md rule 4, when bypassing the fixture layer, consumers import { launch } from "cloakbrowser" directly.

Binary footprint

On first launch the stealth Chromium binary (~200 MB) is auto- downloaded to ~/.cache/cloakbrowser/. CI runners pre-cache it via npx cloakbrowser install in the setup step (parity with playwright install chromium).

Documentation tree

  • build-cloakserve-url — buildCloakServeUrl constructs the WebSocket / HTTP endpoint URL for cloakserve, the cloakbrowser CDP multiplexer th…
  • cloakserve-connect — connectCloakServe connects Playwright to a running cloakserve CDP multiplexer over chromium.connectOverCDP(...),…
  • config — (no submodules)
  • console-monitor — (no submodules)
  • codes — TESTING_E2E_ERROR_CODES is the frozen registry of every failure code @suaveplan/testing-e2e emits. All codes carry…
  • testing-e2e-error — TestingE2eError is the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing…
  • extension-fixture — launchWithExtension starts a stealth Chromium persistent browser context with an unpacked browser extension loaded, t…
    • launch-with-extension — launchWithExtension starts a stealth Chromium persistent browser context with an unpacked browser extension loaded, t…
  • fixtures — extendedTest is the Playwright test function pre-extended with the fixtures this package ships, and — critically —…
    • extended-test — extendedTest is the Playwright test function pre-extended with the fixtures this package ships, and — critically —…
  • dismiss-dialog — dismissDialog attaches a one-shot handler to the next page.on("dialog") event, with the caller choosing between `ac…
  • mock-clipboard — mockClipboard installs a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p…
  • mock-geolocation — mockGeolocation pins a Playwright page to a fixed { latitude, longitude } so tests that exercise location-aware fea…
  • screenshot-on-failure — screenshotOnFailure captures a full-page screenshot when a Playwright test fails and attaches it to the TestInfo re…
  • wait-for-network-idle — waitForNetworkIdle suspends until a Playwright page has had zero in-flight requests for at least idleMs consecutive…
  • multi-session — (no submodules)
  • network-monitor — (no submodules)
  • observability — (no submodules)
  • page-objects — (no submodules)
  • presets — Ready-made CloakOptions bundles for the most common cloakbrowser deployment shapes. Pulled from the official CloakBro…
    • stealth-presets — Ready-made CloakOptions bundles for the most common cloakbrowser deployment shapes. Pulled from the official CloakBro…
- [create-playwright-config](./src/config/create-playwright-config.md) — _(no submodules)_- [console-monitor](./src/console-monitor/console-monitor.md) — _(no submodules)_- [console-monitor](./src/console-monitor/console-monitor.md) — _(no submodules)_- [codes](./src/errors/codes.md) — `TESTING_E2E_ERROR_CODES` is the frozen registry of every failure code `@suaveplan/testing-e2e` emits. All codes carry…

Install

bun add @suaveplan/testing-e2e

Requires @playwright/test and cloakbrowser (installed automatically as direct dependencies). On first launch cloakbrowser auto-downloads the stealth Chromium binary; pre-cache in CI with npx cloakbrowser install.

Quick Start

Playwright config

// playwright.config.ts
import { createPlaywrightConfig } from "@suaveplan/testing-e2e/config";

export default createPlaywrightConfig({
  baseURL: "http://localhost:3000",
  testDir: "e2e",
  projects: [
    { name: "chromium", use: { browserName: "chromium" } },
  ],
});

Page object + stealth extended fixtures

// playwright.config.ts — cloak options for the default browser fixture
import { createPlaywrightConfig } from "@suaveplan/testing-e2e/config";

export default createPlaywrightConfig({
  baseURL: "http://localhost:3000",
  testDir: "e2e",
  use: {
    cloak: {
      headless: true,
      humanize: true,
      geoip: true,
      proxy: "socks5://user:pass@residential:1080",
    },
  },
});
// e2e/pages/login.page.ts
import { PageObject } from "@suaveplan/testing-e2e/page-objects";

export class LoginPage extends PageObject {
  public readonly path = "/login";

  get emailInput() { return this.findByLabel("Email"); }
  get submitButton() { return this.findByRole("button", { name: /sign in/i }); }
}

// e2e/login.spec.ts — runs against a Cloudflare-walled app
import { extendedTest as test, expect } from "@suaveplan/testing-e2e/fixtures";
import { waitForNetworkIdle } from "@suaveplan/testing-e2e/helpers";
import { LoginPage } from "./pages/login.page.js";

test("signs in through Cloudflare Turnstile", async ({ page }) => {
  const login = new LoginPage(page);
  await login.navigate();                       // Turnstile lets us through
  await login.emailInput.fill("user@example.com");
  await login.submitButton.click();
  await waitForNetworkIdle(page);
  await expect(page).toHaveURL("/dashboard");
});

Programmatic launch (outside the Playwright runner)

import { launchBrowserWithCloak } from "@suaveplan/testing-e2e/fixtures";

const browser = await launchBrowserWithCloak({
  humanize: true,
  geoip: true,
  proxy: "http://user:pass@proxy:8080",
});
const ctx = await browser.newContext();
const page = await ctx.newPage();
await page.goto("https://bot.incolumitas.com");
console.log(await page.title());
await browser.close();

Extension fixture (stealth + persistent profile)

import { launchWithExtension } from "@suaveplan/testing-e2e/extension-fixture";

const { context, extensionId } = await launchWithExtension({
  extensionPath: "/path/to/unpacked-extension",
  userDataDir: "/tmp/profile",
  launchOptions: { humanize: true, geoip: true },
});

Cloakserve CDP server (shared container, N parallel workers)

# One container, all your test workers share it
cd packages/testing/testing-e2e/docker
docker compose up -d cloakserve
import { connectCloakServe, stealthMax } from "@suaveplan/testing-e2e";

const browser = await connectCloakServe({
  url: "http://localhost:9222",
  fingerprint: 11111,                        // per-worker seed
  timezone: "America/New_York",
  locale: "en-US",
  proxy: process.env.RESIDENTIAL_PROXY,
  geoip: true,
});

Stealth presets

// playwright.config.ts
import { defineConfig } from "@playwright/test";
import { stealthMax } from "@suaveplan/testing-e2e";

export default defineConfig({
  use: {
    // Upstream-recommended config: residential proxy + geoip + headed + humanize.
    cloak: stealthMax(process.env.RESIDENTIAL_PROXY!),
  },
});

STEALTH_DEFAULT_CLOAK / STEALTH_HEADED_CLOAK are also exported for the lighter shapes. See src/presets/stealth-presets.md for the full menu.

Docker bundle

packages/testing/testing-e2e/docker/ ships:

  • Dockerfile.cloakserve — extends cloakhq/cloakbrowser, adds the Kasada / Akamai font set, runs cloakserve on 9222
  • Dockerfile.manager — extends cloakhq/cloakbrowser-manager, exposes 8080 with a cloakprofiles named volume for persistence
  • docker-compose.yml — both services on 127.0.0.1, with the manager gated behind the manager compose profile
  • .env.example — pinnable CLOAKBROWSER_TAG, MANAGER_TAG, and MANAGER_AUTH_TOKEN

See docker/README.md for the full operator playbook.

Modules

Subpath Module Description
@suaveplan/testing-e2e/config src/config/create-playwright-config.md createPlaywrightConfig — emits a PlaywrightTestConfig with WSL2-safe defaults (fullyParallel: false, trace/screenshot/video retention) and automatic CI mode (retries: 2, workers: 1)
@suaveplan/testing-e2e/page-objects src/page-objects/page-object.md Abstract PageObject base class — typed wrapper around a Playwright Page with navigate(), waitForReady(), and accessibility-first locator helpers (findByRole, findByLabel, findByText)
@suaveplan/testing-e2e/fixtures src/fixtures/extended-test.md extendedTest — test.extend(...) with the browser worker fixture overridden to launch cloakbrowser; plus apiContext (isolated APIRequestContext, browser-free) and freshPage (isolated browser context + page); also exports launchBrowserWithCloak and expect
@suaveplan/testing-e2e/helpers src/helpers/wait-for-network-idle.md waitForNetworkIdle — polls in-flight request count and resolves once the network has been idle for idleMs (default 500 ms); throws WaitTimeoutError on timeout
src/helpers/mock-clipboard.md mockClipboard — installs a programmatic in-page clipboard so tests can assert writeText/readText without OS permissions
src/helpers/mock-geolocation.md mockGeolocation — grants geolocation permission and sets static latitude/longitude/accuracy on a BrowserContext
src/helpers/screenshot-on-failure.md screenshotOnFailure — captures a full-page screenshot named after the failing test; useful as a manual teardown hook alongside Playwright's built-in artifact retention
src/helpers/dismiss-dialog.md dismissDialog — registers a one-shot dialog handler that accepts or dismisses the next browser dialog (alert, confirm, prompt)
@suaveplan/testing-e2e/errors src/errors/testing-e2e-error.md Typed error classes (NavigationError, WaitTimeoutError, AbortedError, CloakLaunchError) + classifyCloakError / wrapCloakError helpers
src/errors/codes.md TESTING_E2E_ERROR_CODES registry
(observability) src/observability/instrumented.md instrumented — optional OTel wrapper (gated by TESTING_E2E_OTEL_ENABLED=1) that records call counts and duration histograms for package entrypoints