# tape-six-playwright > A helper for [tape-six](https://github.com/uhop/tape-six) that runs test files in a headless browser via Playwright. Each test file runs in its own browser context (page + iframe) in Chromium, Firefox, or WebKit (default Chromium, selectable via `--browser`). The npm package name is `tape-six-playwright` and the CLI command is `tape6-playwright`. - Real browser environment: tests run in a headless engine (Chromium, Firefox, or WebKit) with full DOM and browser API access - Per-context isolation: each test file runs in its own browser context (isolated cookies/storage), in an iframe inside that context's page - Multiple engines: `--browser` / `TAPE6_BROWSER` selects `chromium` (default), `firefox`, or `webkit` - Cross-runtime: Node, Deno, and Bun with the same test files - Drop-in companion for `tape6` (worker-thread runner) and `tape6-proc` (subprocess runner) - Same configuration format as `tape-six` - Parallel execution with configurable concurrency - TAP, TTY (colored), JSONL, and minimal output formats ## Install ```bash npm i -D tape-six-playwright ``` Playwright's bundled Chromium is installed automatically via `postinstall`. Firefox and WebKit are optional — add them with `npm run browser:all` (or `npx playwright install firefox webkit`; on Linux add `npx playwright install-deps`). ## Quick start Write a test (`tests/test-dom.js`): ```js import test from 'tape-six' test('DOM works', t => { const el = document.createElement('div') el.textContent = 'hello' document.body.appendChild(el) t.equal(document.body.lastChild.textContent, 'hello', 'element created') }) ``` Run all configured tests via Playwright: ```bash tape6-playwright --start-server --flags FO ``` ## CLI: tape6-playwright Runs test files in parallel, each in its own browser context inside a headless engine (Chromium by default; Firefox or WebKit via `--browser`). ```bash tape6-playwright [options] [patterns...] ``` ### Options - `--flags FLAGS` (`-f`) — output control flags (see Supported flags below). - `--par N` (`-p`) — number of parallel iframes. Default: all CPU cores (via `os.availableParallelism()` or `navigator.hardwareConcurrency`). - `--browser NAME` (`-b`) — browser engine: `chromium` (default), `firefox`, or `webkit`. Overrides `TAPE6_BROWSER`. Only Chromium is installed by `postinstall`; a missing/unrunnable engine fails the run with an `npx playwright install` / `install-deps` hint. - `--browsers LIST` — multi-engine fan-out: comma-separated engine names or `all` (env: `TAPE6_BROWSERS`; overrides `--browser`). Runs the full suite once per engine sequentially — fresh reporter and per-engine summary each — then prints a final `Browsers: PASS|FAIL, ...` line; exits non-zero if any engine fails. Duplicates are deduped; a failed-to-launch engine records FAIL and the remaining engines still run. - `--start-server` — auto-start `tape6-server` if not already running. - `--h2` — HTTP/2 mode: implies an `https:` server URL and is passed through to a self-launched server. Overrides `TAPE6_PROTOCOL` and the `tape6.server.protocol` config (flag > env > config, mirroring the server's own resolution). - `--server-url URL` (`-u`) — server URL. Overrides `TAPE6_SERVER_URL` and `HOST`/`PORT`. An explicit `https:` URL enables TLS handling even without `--h2`. - `--self` — prints the absolute path to `tape6-playwright.js` and exits. Used in cross-runtime scripts. - `--info` — prints runtime, reporter, flags, parallelism, and resolved test files, then exits. Does not require a running server. - `--help` (`-h`) — shows help message with all options and flag descriptions, then exits. - `--version` (`-v`) — shows version and exits. - Positional arguments: test file glob patterns. If none given, resolved from configuration. - Options accept `--flags FO` or `--flags=FO`. The `=` form does not support quoting. ### Examples ```bash # Run all configured tests tape6-playwright --start-server --flags FO # Run specific test files tape6-playwright --start-server tests/test-dom.js # Limit parallelism tape6-playwright --start-server --par 2 --flags FO # Run on Firefox (or WebKit) tape6-playwright --start-server --browser firefox --flags FO TAPE6_BROWSER=webkit tape6-playwright --start-server --flags FO # Fan out over several engines in one invocation tape6-playwright --start-server --browsers all --flags FO tape6-playwright --start-server --browsers chromium,webkit --flags FO # Use with already-running server tape6-playwright --flags FO # Run over HTTP/2 (https; self-signed certificate handled automatically) tape6-playwright --h2 --start-server --flags FO tape6-playwright -u https://localhost:3000 --flags FO ``` ## Cross-runtime usage `tape6-playwright` is a Node CLI by default. For Bun and Deno, use the `--self` flag to get the script path: ```json { "scripts": { "test": "tape6-playwright --start-server --flags FO", "test:bun": "bun run `tape6-playwright --self` --start-server --flags FO", "test:deno": "deno run -A `tape6-playwright --self` --start-server --flags FO" } } ``` ## Supported flags Flags are a string of characters. Uppercase = enabled, lowercase = disabled. - `F` — Failures only: show only failed tests. - `T` — show Time for each test. - `B` — show Banner with summary. - `D` — show Data of failed tests. - `O` — fail Once: stop at first failure. - `N` — show assert Number. - `M` — Monochrome: no colors. - `C` — don't Capture console output. - `H` — Hide streams and console output. Usage: ```bash tape6-playwright --start-server --flags FO TAPE6_FLAGS=FO tape6-playwright --start-server ``` ## Server `tape6-playwright` requires `tape6-server` (from `tape-six`) to serve test files to the browser. - `--start-server`: auto-starts the server before running tests. - Without it: the server must already be running. The runner prints instructions if it's unreachable. Probes are deadline-bounded (3s per request); a TLS request answered in plaintext (an h1 server on an `https:` URL) is reported as a protocol mismatch instead of hanging. - Server URL: `TAPE6_SERVER_URL` env var, or `HOST`/`PORT`, or default `http://localhost:3000`. - Server endpoints used: `GET /--tests` (test file list), `GET /--patterns?q=...` (filtered file list), `GET /--importmap` (import map). - HTTP/2 (tape-six 1.12+): enable with `--h2`, `TAPE6_PROTOCOL=h2`, or `tape6.server.protocol` in config — the runner resolves flag > env > config exactly like the server, upgrades the server URL to `https:`, and passes `--h2` to a self-launched server. The h2 server mode is Node-only; under Bun/Deno the server child is spawned with `node` from `PATH`. HTTP/1.1 stays the default (self-signed TLS blocks service-worker registration; h2 exists for h2-only features such as Chromium's `fetch()` request-body streaming). - Certificates in h2 mode: browser contexts run with `ignoreHTTPSErrors`; the runner's own control requests (tape-six's `utils/controlFetch.js`) go through `node:https` with trust scoped to those requests — `TAPE6_CERT` pinned as CA when set, else the server's cached auto-generated certificate (`node_modules/.cache/tape6/cert.pem`), else relaxed verification. Never process-wide (`NODE_TLS_REJECT_UNAUTHORIZED` is not touched). ## Configuration Configuration is read from `tape6.json` or the `"tape6"` section of `package.json` (same format as `tape-six`): ```json { "tape6": { "browser": ["/tests/test-*.html"], "tests": ["/tests/test-*.*js"], "importmap": { "imports": { "tape-six": "/node_modules/tape-six/index.js", "tape-six/": "/node_modules/tape-six/src/" } } } } ``` The `importmap` section is served by `tape6-server` at `/--importmap` and injected into each iframe for module resolution. ## Environment variables - `TAPE6_FLAGS` — flags string (combined with `--flags` CLI argument). - `TAPE6_PAR` — number of parallel iframes (overridden by `--par`). - `TAPE6_TAP` — force TAP reporter (any non-empty value). - `TAPE6_JSONL` — force JSONL reporter (any non-empty value). - `TAPE6_MIN` — force minimal reporter (any non-empty value). - `TAPE6_SERVER_URL` — full server URL override (e.g. `http://localhost:4000`). Overridden by `--server-url`. - `TAPE6_PROTOCOL` — `h1` (default) or `h2`. Overridden by `--h2`; overrides `tape6.server.protocol` config. - `TAPE6_CERT` / `TAPE6_KEY` — TLS certificate/key paths for h2 (e.g. from mkcert). The server serves with them; the runner pins `TAPE6_CERT` as the CA for its control requests. - `TAPE6_BROWSER` — browser engine: `chromium` (default), `firefox`, or `webkit`. Overridden by `--browser` (precedence: CLI > env > default). - `TAPE6_BROWSERS` — multi-engine fan-out list (comma-separated or `all`). Overridden by `--browsers`; when set (either way), the fan-out overrides `--browser`/`TAPE6_BROWSER`. - `HOST` — server hostname (default: `localhost`). - `PORT` — server port (default: `3000`). - `TAPE6_GRACE_TIMEOUT` — control channel: ms a worker gets to drain (run cleanup hooks) after a terminate, before its browser context is force-closed (default: `5000`). - `TAPE6_WORKER_TIMEOUT` — control channel: per-worker wall-clock deadline in ms; on expiry the worker is drained then force-killed (default: `0`, disabled). Both are honored by a `tape-six` that ships the hub control plane. ## Architecture ### Entry point `bin/tape6-playwright.js` is the CLI entry point: - With `--help`/`-h`: prints usage and all options, then exits. - With `--version`/`-v`: prints version, then exits. - With `--self`: prints its own absolute path and exits. - Otherwise: delegates to `bin/tape6-playwright-node.js`. ### Main CLI (`bin/tape6-playwright-node.js`) A single `runDriverCli({packageUrl, commandName, description, supportedBrowsers, TestWorker})` call into `tape-six/driver/cli.js` (the browser-driver kit, tape-six 1.15.0+). The kit owns the whole driver-bin flow: 1. Parses CLI arguments (`--flags`, `--par`, `--browser`, `--browsers`, `--start-server`, `--h2`, `--server-url`, `--info`, positional test patterns) and validates the engine selection against `supportedBrowsers`. 2. Resolves the protocol the way the server does (`--h2` > `TAPE6_PROTOCOL` > `tape6.server.protocol` config > `h1`); in h2 mode upgrades the server URL scheme to `https:`. 3. Initializes the reporter. 4. Ensures `tape6-server` is reachable (auto-starts if `--start-server`, passing `--h2` for an `https:` URL; under Bun/Deno the h2 server child runs on `node`). Probes have a per-request deadline; a TLS-vs-plaintext mismatch is reported explicitly, and self-launch waits briefly for the port to free after one (chained h1 → h2 runs). 5. Fetches test files from server via `GET /--patterns?q=...` (if patterns given) or `GET /--tests`. 6. Fetches importmap from `GET /--importmap`. All control requests go through tape-six's `utils/controlFetch.js`, which tolerates the server's self-signed certificate on `https:` with request-scoped trust. 7. For each selected engine (one by default; several with `--browsers`), creates a `TestWorker` instance and executes all test files — a fresh reporter per engine so counts and summaries are per-engine. 8. Reports final results (plus a per-engine `Browsers: ... PASS|FAIL` line when fanning out) and exits with code 0 (success) or 1 (any failure on any engine). 9. Kills auto-started server on exit. ### TestWorker (`src/TestWorker.js`) The Playwright adapter for the kit base in `tape-six/driver/TestWorker.js`. The base owns the task lifecycle — per-task `BrowserContext` → `Page` (full origin/storage isolation) with completion driven by the page `close` event, the `__tape6_reporter` / `__tape6_error` page functions, iframe injection via `tape-six/driver/bootstrap.js`, cooperative drain + `graceTimeout` force-kill, launch-failure reporting (a missing engine fails the run rather than reporting a false pass), and cleanup. The adapter supplies the driver-specific members: - **`supportedBrowsers`** — `['chromium', 'firefox', 'webkit']`; also exported and passed to `runDriverCli` as the single source of truth for CLI validation. - **`pageErrorEvent`** — `'pageerror'` (Playwright's page-level error event). - **`launchBrowser(name)`** — `playwright[name].launch(...)`, headless, `--no-sandbox` on Chromium only; wraps a launch failure with an `npx playwright install` / `install-deps` hint. - **`newContext(browser, {insecure})`** — an isolated context per task, created with `ignoreHTTPSErrors` when the server URL is `https:` (the h2 self-signed certificate). Types ship as a hand-written sidecar (`src/TestWorker.d.ts`, advertised via `// @ts-self-types` in `TestWorker.js`), built on tape-six's shipped driver-kit types: it narrows the kit base's deliberately-`any` driver handles to Playwright's `Browser` / `BrowserContext`. The pre-kit `EventServerOptions` module augmentation and constructor union are gone — tape-six ≥ 1.14.1 typings made both unnecessary. ### Browser engines The engine is chosen with `--browser ` / `-b`, or `TAPE6_BROWSER` (precedence: CLI > env > default `chromium`). The CLI validates the value against `supportedBrowsers` (exported from `src/TestWorker.js` — the single source of truth) and exits with an error on an unknown engine. The kit base then resolves it and calls the adapter's `launchBrowser(name)` — `playwright[name].launch(...)`, applying `--no-sandbox` to Chromium only (Firefox and WebKit launch without it). The per-context model, iframe injection, data plane, and control channel are identical across all three engines — only the launched browser differs. `postinstall` fetches only Chromium; Firefox and WebKit are installed on demand (`npm run browser:all`, or `npx playwright install firefox webkit`, plus `npx playwright install-deps` on Linux). Requesting an engine that isn't installed (or can't run for lack of system libraries) surfaces a clear hint and fails the run. `--browsers` (plural) fans the suite out over several engines in one invocation — sequential runs, one `TestWorker` per engine, per-engine summaries, and a final per-engine PASS/FAIL verdict. This is the cheap way to catch cross-engine web-platform gaps (an engine missing a spec method — e.g. a Web Streams member — passes on the others and fails only there). The sibling package `tape-six-puppeteer` exposes the same `--browser` / `TAPE6_BROWSER` contract, minus `webkit` (Puppeteer drives only Chromium-family and Firefox). ### Iframe lifecycle For `.html` files: 1. Set iframe `src` to the file URL with query parameters (`id`, `test-file-name`, `flags`). 2. The HTML file loads `tape-six` which auto-detects `window.parent.__tape6_reporter`. For `.js`/`.mjs` files: 1. Create iframe, write an HTML document with `importmap` and a dynamic ` ``` ## Links - Docs: https://github.com/uhop/tape-six-playwright/wiki - npm: https://www.npmjs.com/package/tape-six-playwright - tape-six: https://github.com/uhop/tape-six - tape-six LLM reference: https://github.com/uhop/tape-six/blob/master/llms.txt