Files
suaveplan/openspec/changes/swap-testing-e2e-cloakbrowser/proposal.md
2026-05-27 23:29:53 +01:00

4.8 KiB

swap-testing-e2e-cloakbrowser

Why

@playwright/test ships a stock Chromium that is trivially fingerprinted as automation (navigator.webdriver === true, HeadlessChrome UA, missing window.chrome, GPU/canvas/audio leaks, CDP detection). E2E suites that exercise production-like flows against bot-aware infrastructure (Cloudflare Turnstile, reCAPTCHA v3, ShieldSquare, FingerprintJS, BrowserScan) either fail outright or skew metrics on the first request.

CloakBrowser (cloakbrowser, v0.3.28) is a real Chromium binary with 49 source-level C++ patches covering canvas, WebGL, audio, fonts, GPU, screen, WebRTC, network timing, automation signals, and CDP input behaviour. It is a drop-in replacement at the browser-launch layer: the returned object is a playwright-core Browser and works with every existing Playwright test, fixture, page-object, and helper without API changes.

This proposal swaps every browser-launch call inside @suaveplan/testing-e2e to cloakbrowser, retains @playwright/test as the test runner (CloakBrowser does not provide one), and exposes the stealth-specific knobs (humanize, proxy, geoip, launchPersistentContext, extension support) as first-class API surface.

What Changes

  • ADDED: CLOAK_LAUNCH_FAILED, CLOAK_BINARY_MISSING, CLOAK_PROXY_INVALID error codes + CloakLaunchError class + classifyCloakError helper that turns raw cloakbrowser errors into classified TestingE2eError instances with remediation hints.
  • ADDED: @suaveplan/testing-e2e/cloakserve subpath — connectCloakServe(options, chromium?) + buildCloakServeUrl(options) pair that wraps chromium.connectOverCDP(...) for the cloakserve CDP multiplexer. Strongly-typed query-parameter surface (fingerprint, timezone, locale, platform, GPU vendor / renderer, hardware concurrency, device memory, screen dimensions, proxy, geoip). Errors wrapped in CloakLaunchError.
  • ADDED: @suaveplan/testing-e2e/presets subpath — stealth presets matching the upstream README's "Recommended config for anti-bot sites" block. STEALTH_DEFAULT_CLOAK, STEALTH_HEADED_CLOAK, stealthMax(proxy), stealthMaxHeadless(proxy).
  • ADDED: tests/no-disallowed.test.ts rule against waitForTimeout / wait_for_timeout. Both forms emit CDP traffic that reCAPTCHA v3 / Enterprise behavioural scorers detect; the upstream README documents this explicitly. Test files excluded.
  • ADDED: docker/ bundle — 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), docker-compose.yml binding both to 127.0.0.1 with the manager gated behind the manager compose profile, .env.example for pinned tags + AUTH_TOKEN, operator README.md.
  • MODIFIED: extendedTest's browser fixture now launches via cloakbrowser.launch() instead of the stock Playwright chromium fixture. freshPage and any downstream fixture composition keep the same signature. The launcher is unit-test-injectable via the launchBrowserWithCloak(opts, injectedLaunch?) helper.
  • MODIFIED: launchWithExtension accepts an injectable launchPersistentContext function (default: cloakbrowser's). The legacy chromium: BrowserType parameter is removed.
  • MODIFIED: packages/testing/testing-e2e/package.json adds cloakbrowser: ^0.3.28 as a direct dependency. (The dep is pinned in-package rather than added to workspaces.catalogs.testing to keep this change isolated from concurrent in-flight work that also touches the root catalog; promote to the testing catalog as a follow-up if other packages start consuming cloakbrowser.)
  • MODIFIED: Package description, README updated. No public re-exports of cloakbrowser symbols — per CLAUDE.md rule 4, consumers import { launch } from "cloakbrowser" directly when bypassing the fixture layer.

Impact

  • Affected specs: testing-e2e.
  • Affected code: all six consumer packages currently importing from @suaveplan/testing-e2e continue to work unchanged — the browser launcher swap is transparent to existing tests because the returned Browser object is the same playwright-core Browser type.
  • Binary footprint: CI runners gain a ~200MB stealth Chromium download on first run (cached under ~/.cache/cloakbrowser/). Acceptable: the alternative is playwright install chromium (~170MB) on every @playwright/test consumer.
  • Out of scope: Python flavour (cloakbrowser PyPI), cloakserve CDP multiplexer, cloakbrowser-manager Docker profile UI — none are consumed by the genesis monorepo today.