@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.browseris launched viacloakbrowser.launch. The returned object is still a PlaywrightBrowserfromplaywright-core— every fixture, page object, helper, and monitor works unchanged.- A new worker option
cloak: CloakOptionsflows into the launcher. Set per project inplaywright.config.ts:use: { cloak: { humanize: true, geoip: true, proxy: "…" } }. launchWithExtensiondefaults tocloakbrowser.launchPersistentContextand exposes alaunchPersistentContextinjector for tests / profile managers.- Failures classify into
TESTING_E2E.CLOAK.{LAUNCH_FAILED,BINARY_MISSING,PROXY_INVALID}viaclassifyCloakError+wrapCloakError, wrapped inCloakLaunchError. @playwright/teststays as the test runner — cloakbrowser is a drop-in browser-launch replacement, not a runner replacement.- No public re-exports of
cloakbrowsersymbols. Per CLAUDE.md rule 4, when bypassing the fixture layer, consumersimport { 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 —
buildCloakServeUrlconstructs the WebSocket / HTTP endpoint URL forcloakserve, the cloakbrowser CDP multiplexer th… - cloakserve-connect —
connectCloakServeconnects Playwright to a runningcloakserveCDP multiplexer overchromium.connectOverCDP(...),… - config — (no submodules)
- create-playwright-config — (no submodules)
- console-monitor — (no submodules)
- console-monitor — (no submodules)
- codes —
TESTING_E2E_ERROR_CODESis the frozen registry of every failure code@suaveplan/testing-e2eemits. All codes carry… - testing-e2e-error —
TestingE2eErroris the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing… - extension-fixture —
launchWithExtensionstarts a stealth Chromium persistent browser context with an unpacked browser extension loaded, t…- launch-with-extension —
launchWithExtensionstarts a stealth Chromium persistent browser context with an unpacked browser extension loaded, t…
- launch-with-extension —
- fixtures —
extendedTestis the Playwrighttestfunction pre-extended with the fixtures this package ships, and — critically —…- extended-test —
extendedTestis the Playwrighttestfunction pre-extended with the fixtures this package ships, and — critically —…
- extended-test —
- dismiss-dialog —
dismissDialogattaches a one-shot handler to the nextpage.on("dialog")event, with the caller choosing between `ac… - mock-clipboard —
mockClipboardinstalls a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p… - mock-geolocation —
mockGeolocationpins a Playwright page to a fixed{ latitude, longitude }so tests that exercise location-aware fea… - screenshot-on-failure —
screenshotOnFailurecaptures a full-page screenshot when a Playwright test fails and attaches it to theTestInfore… - wait-for-network-idle —
waitForNetworkIdlesuspends until a Playwright page has had zero in-flight requests for at leastidleMsconsecutive… - multi-session — (no submodules)
- create-multi-session — (no submodules)
- network-monitor — (no submodules)
- network-monitor — (no submodules)
- observability — (no submodules)
- instrumented — (no submodules)
- page-objects — (no submodules)
- page-object — (no submodules)
- presets — Ready-made
CloakOptionsbundles for the most common cloakbrowser deployment shapes. Pulled from the official CloakBro…- stealth-presets — Ready-made
CloakOptionsbundles for the most common cloakbrowser deployment shapes. Pulled from the official CloakBro…
- stealth-presets — Ready-made
- testing-e2e-error —
TestingE2eErroris the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing… - extension-fixture — (no submodules)- launch-with-extension — (no submodules)- fixtures — (no submodules)- extended-test — (no submodules)- dismiss-dialog —
dismissDialogattaches a one-shot handler to the nextpage.on("dialog")event, with the caller choosing between `ac… - mock-clipboard —
mockClipboardinstalls a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p… - mock-geolocation —
mockGeolocationpins a Playwright page to a fixed{ latitude, longitude }so tests that exercise location-aware fea… - screenshot-on-failure —
screenshotOnFailurecaptures a full-page screenshot when a Playwright test fails and attaches it to theTestInfore… - wait-for-network-idle —
waitForNetworkIdlesuspends until a Playwright page has had zero in-flight requests for at leastidleMsconsecutive… - multi-session — (no submodules)- create-multi-session — (no submodules)- network-monitor — (no submodules)- network-monitor — (no submodules)- observability — (no submodules)- instrumented — (no submodules)- page-objects — (no submodules)- page-object — (no submodules)- create-playwright-config — (no submodules)- console-monitor — (no submodules)- console-monitor — (no submodules)- codes —
TESTING_E2E_ERROR_CODESis the frozen registry of every failure code@suaveplan/testing-e2eemits. All codes carry… - testing-e2e-error —
TestingE2eErroris the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing… - extension-fixture — (no submodules)- launch-with-extension — (no submodules)- fixtures — (no submodules)- extended-test — (no submodules)- dismiss-dialog —
dismissDialogattaches a one-shot handler to the nextpage.on("dialog")event, with the caller choosing between `ac… - mock-clipboard —
mockClipboardinstalls a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p… - mock-geolocation —
mockGeolocationpins a Playwright page to a fixed{ latitude, longitude }so tests that exercise location-aware fea… - screenshot-on-failure —
screenshotOnFailurecaptures a full-page screenshot when a Playwright test fails and attaches it to theTestInfore… - wait-for-network-idle —
waitForNetworkIdlesuspends until a Playwright page has had zero in-flight requests for at leastidleMsconsecutive… - multi-session — (no submodules)- create-multi-session — (no submodules)- network-monitor — (no submodules)- network-monitor — (no submodules)- observability — (no submodules)- instrumented — (no submodules)- page-objects — (no submodules)- page-object — (no submodules)- create-playwright-config — (no submodules)- console-monitor — (no submodules)- console-monitor — (no submodules)- codes —
TESTING_E2E_ERROR_CODESis the frozen registry of every failure code@suaveplan/testing-e2eemits. All codes carry… - testing-e2e-error —
TestingE2eErroris the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing… - extension-fixture — (no submodules)- launch-with-extension — (no submodules)- fixtures — (no submodules)- extended-test — (no submodules)- dismiss-dialog —
dismissDialogattaches a one-shot handler to the nextpage.on("dialog")event, with the caller choosing between `ac… - mock-clipboard —
mockClipboardinstalls a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p… - mock-geolocation —
mockGeolocationpins a Playwright page to a fixed{ latitude, longitude }so tests that exercise location-aware fea… - screenshot-on-failure —
screenshotOnFailurecaptures a full-page screenshot when a Playwright test fails and attaches it to theTestInfore… - wait-for-network-idle —
waitForNetworkIdlesuspends until a Playwright page has had zero in-flight requests for at leastidleMsconsecutive… - multi-session — (no submodules)- create-multi-session — (no submodules)- network-monitor — (no submodules)- network-monitor — (no submodules)- observability — (no submodules)- instrumented — (no submodules)- page-objects — (no submodules)- page-object — (no submodules)- create-playwright-config — (no submodules)- console-monitor — (no submodules) - console-monitor — (no submodules)- codes —
TESTING_E2E_ERROR_CODESis the frozen registry of every failure code@suaveplan/testing-e2eemits. All codes carry… - testing-e2e-error —
TestingE2eErroris the structured error class thrown by every helper, fixture, and page object in `@suaveplan/testing… - extension-fixture — (no submodules) - launch-with-extension — (no submodules)- fixtures — (no submodules) - extended-test — (no submodules)- dismiss-dialog —
dismissDialogattaches a one-shot handler to the nextpage.on("dialog")event, with the caller choosing between `ac… - mock-clipboard —
mockClipboardinstalls a deterministic, in-memory clipboard implementation on the navigator object for a Playwright p… - mock-geolocation —
mockGeolocationpins a Playwright page to a fixed{ latitude, longitude }so tests that exercise location-aware fea… - screenshot-on-failure —
screenshotOnFailurecaptures a full-page screenshot when a Playwright test fails and attaches it to theTestInfore… - wait-for-network-idle —
waitForNetworkIdlesuspends until a Playwright page has had zero in-flight requests for at leastidleMsconsecutive… - multi-session — (no submodules) - create-multi-session — (no submodules)- network-monitor — (no submodules) - network-monitor — (no submodules)- observability — (no submodules) - instrumented — (no submodules)- page-objects — (no submodules) - page-object — (no submodules)
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— extendscloakhq/cloakbrowser, adds the Kasada / Akamai font set, runscloakserveon 9222Dockerfile.manager— extendscloakhq/cloakbrowser-manager, exposes 8080 with acloakprofilesnamed volume for persistencedocker-compose.yml— both services on127.0.0.1, with the manager gated behind themanagercompose profile.env.example— pinnableCLOAKBROWSER_TAG,MANAGER_TAG, andMANAGER_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 |