# cloakserve-connect ## Purpose `connectCloakServe` connects Playwright to a running [`cloakserve`](https://github.com/CloakHQ/CloakBrowser#cdp-server-mode) CDP multiplexer over `chromium.connectOverCDP(...)`, with the fingerprint / proxy / geoip / locale parameters expressed as a strongly-typed options bundle rather than a hand-rolled query string. The helper exists so test suites can share a single Docker container of `cloakhq/cloakbrowser` running `cloakserve` across many parallel workers — each worker requests its own seeded fingerprint via a URL parameter, cloakserve spawns (or reuses) a stealth Chromium process for that seed, and you save the ~200 MB binary download + launch latency that an in-process `cloakbrowser.launch()` per worker would incur. ## Features - Strongly-typed `CloakServeConnectOptions` (mirrors the documented cloakserve query-param surface) - Uses {@link buildCloakServeUrl} for URL composition - Pluggable Playwright `chromium` driver (defaults to `@playwright/test`'s built-in `chromium`) - Errors classified by `classifyCloakError` and wrapped in a `CloakLaunchError` with `cloakServeUrl` in `context` - Cache-busting test hook (`_resetCloakServeChromiumCache`) ## Usage: Basic Example ```typescript import { connectCloakServe } from "@suaveplan/testing-e2e"; const browser = await connectCloakServe({ url: "http://localhost:9222", fingerprint: 11111, }); const page = await browser.newPage(); await page.goto("https://protected-site.com"); ``` ## Usage: Advanced Example ```typescript // Parallel workers share one cloakserve container. import { connectCloakServe } from "@suaveplan/testing-e2e"; import { test } from "@suaveplan/testing-e2e"; test("worker-isolated identity", async ({}, testInfo) => { // Per-worker seed gives each worker an isolated Chromium process. const browser = await connectCloakServe({ url: process.env.CLOAKSERVE_URL ?? "http://localhost:9222", fingerprint: 10000 + testInfo.parallelIndex, timezone: "America/New_York", locale: "en-US", proxy: process.env.PROXY, geoip: true, }); try { const ctx = await browser.newContext(); const page = await ctx.newPage(); await page.goto("https://example.com"); await ctx.close(); } finally { await browser.close(); } }); ``` ## API Reference ### `connectCloakServe(options?, chromium?): Promise` Connects to a cloakserve CDP endpoint and returns a Playwright `Browser`. `chromium` defaults to `@playwright/test`'s built-in. **Throws:** `CloakLaunchError` with `TESTING_E2E.CLOAK.{LAUNCH_FAILED|BINARY_MISSING|PROXY_INVALID}` when `connectOverCDP` rejects. `context.cloakServeUrl` carries the URL that was attempted. ### `_resetCloakServeChromiumCache(): void` Internal hook to reset the lazy dynamic-import cache. Exposed for unit tests; production code should never call this. ## Implementation Notes The `connectOverCDP` call goes through `@playwright/test`'s `chromium` rather than `playwright-core` directly because tests in this project already pins `@playwright/test` as the test runner and Playwright re-exports `chromium` from there. The injected `chromium` parameter only needs `connectOverCDP` — typed as `Pick` so spies are cheap to write. When pointing at a remote cloakserve, **never** expose port 9222 to the public internet without an upstream auth layer. CDP gives full control over the browser; see the security warning in the upstream CloakBrowser README. The bundled `docker-compose.yml` in `packages/testing/testing-e2e/docker/` binds to `127.0.0.1` by default.