This guide covers the architecture, internals, deployment, security, and operational concerns of Playwright v1.60.0-next — Microsoft's cross-browser end-to-end testing and automation framework. It is written for platform engineers, DevOps teams, CI/CD administrators, and developers who need to understand how Playwright works under the hood, scale it across infrastructure, and troubleshoot production issues.
For installation walkthroughs, everyday CLI usage, test authoring patterns, and feature guides, see the companion User Guide.
1. Architecture Overview
1.1 Monorepo Structure
Playwright is organized as an npm workspaces monorepo under packages/*. The codebase spans 2,985 files and over 9 million characters of source. Each package has a sharply defined responsibility; understanding these boundaries is essential for anyone modifying or extending the framework.
Core Packages
| Package | Role |
|---|---|
playwright |
Main package — test runner, fixtures, expect matchers, reporters, CLI commands (test, show-report, etc.) |
playwright-core |
Core automation library — browser launching, CDP/protocol transport, server components, CLI commands (install, codegen, open, etc.) |
playwright-test |
Thin re-export wrapper providing the @playwright/test npm package name |
playwright-client |
Client-only package (no bundled browser binaries) |
Browser-Specific Packages
| Package | Role |
|---|---|
playwright-chromium |
Chromium-only automation package |
playwright-firefox |
Firefox-only automation package |
playwright-webkit |
WebKit-only automation package |
playwright-browser-chromium |
Browser download metadata for Chromium |
playwright-browser-firefox |
Browser download metadata for Firefox |
playwright-browser-webkit |
Browser download metadata for WebKit |
Component Testing
| Package | Role |
|---|---|
playwright-ct-core |
Component testing core — mount fixture, router |
playwright-ct-react |
Component testing adapter for React |
playwright-ct-react17 |
Component testing adapter for React 17 |
playwright-ct-vue |
Component testing adapter for Vue |
UI & Tooling Packages
| Package | Role |
|---|---|
html-reporter |
HTML report viewer (React SPA) |
trace-viewer |
Trace viewer (React SPA) |
recorder |
Codegen recorder UI |
dashboard |
Dashboard UI |
playwright-cli-stub |
CLI stub entry point |
Internal Shared Packages
| Package | Role |
|---|---|
protocol |
Protocol type definitions (~259K chars) — the wire protocol spec between client and server |
injected |
Scripts injected into browser pages: selectors, clock, highlights, storage, WebSocket mock |
isomorphic |
Shared utilities: CSS parser, selector parser, locator generators, image utils, ARIA snapshots |
utils |
Node.js utilities: comparators, crypto, debug, env, file utils, host platform detection, profiler, process launcher, zones |
trace |
Trace format handling |
web |
Shared web UI components |
Note
The
protocolpackage is the single source of truth for the wire format between client and server. All dispatchers and channel interfaces are generated or hand-aligned to match these type definitions. Any protocol change must start here.
1.2 Layered Data Flow
Every Playwright operation — whether launched from a test file, the CLI, or a remote connection — follows this layered path:
User Code (test files / scripts)
|
v
playwright (test runner: fixtures, workers, reporters)
|
v
playwright-core (client layer — Browser, Page, Frame API objects)
|
v
Protocol (JSON-RPC messages over pipe or WebSocket)
|
v
Server (browser management, dispatcher hierarchy)
|
v
Chromium / Firefox / WebKit (browser processes)
|
v
Injected Scripts (selectors, clock, highlights, storage, WebSocket mock)
The client layer constructs protocol messages. The server layer dispatches them to browser processes. The injected scripts run inside the browser's JavaScript context to evaluate selectors, manipulate the clock, and perform DOM operations. This separation means the Node.js process never directly touches the browser DOM — all interaction is mediated by the protocol.
1.3 Server Components
PlaywrightServer — A WebSocket server that exposes browser automation over the network. Used for remote browser access, grid setups, and the Playwright service. Configured via run-server CLI command with --port, --host, --path, --max-clients, --mode, and --artifacts-dir options.
DispatcherConnection + Dispatcher Hierarchy — The server-side object graph mirrors the client-side API. Each client-side object (Browser, BrowserContext, Page, Frame, etc.) has a corresponding dispatcher on the server that handles protocol messages and maintains state.
RootDispatcher
└── PlaywrightDispatcher
├── BrowserTypeDispatcher
│ └── BrowserDispatcher
│ └── BrowserContextDispatcher
│ ├── PageDispatcher
│ │ └── FrameDispatcher
│ │ └── ElementHandleDispatcher
│ └── CDPSessionDispatcher
└── ... (25+ dispatcher classes total)
ServerRegistry — Manages browser installations. Extends EventEmitter to notify listeners of installation events. Handles download, verification, and path resolution for all three browser engines.
1.4 Test Runner Architecture
The test runner (playwright package) has four major subsystems:
-
Configuration —
FullConfigInternalparses and validatesplaywright.config.ts.FullProjectInternalhandles per-project configuration including dependencies and teardown ordering. -
Worker Pool —
WorkerMainextendsProcessRunnerto run tests in isolated worker processes. Workers communicate with the main process over IPC. The number of workers is controlled by theworkersconfig option (default:'50%'of CPU cores). -
Fixture System —
FixtureRunnerandFixtureclasses implement a dependency-injection system. Fixtures declare dependencies on other fixtures, and the runner resolves the dependency graph, sets up fixtures in order, and tears them down in reverse order. -
Tracing —
TestTracingmanages trace recording per test. Traces capture screenshots, network activity, DOM snapshots, and console output for post-mortem debugging.
1.5 Browser Patches
Playwright maintains custom patches for the browsers it drives:
| Directory | Purpose |
|---|---|
browser_patches/firefox/ |
Firefox Juggler protocol — a custom CDP-like protocol that enables Playwright to control Firefox internals not exposed by standard APIs |
browser_patches/webkit/ |
WebKit embedder patches for Playwright's WebKit automation |
browser_patches/winldd/ |
Windows DLL dependency checker utility |
These patches are applied to specific browser revisions that Playwright downloads and manages. This is why Playwright bundles its own browser binaries rather than using system-installed browsers.
1.6 Build System
The build toolchain uses a custom esbuild-based builder:
node utils/build/build.js
Key build dependencies:
- TypeScript ^5.9.2
- esbuild — fast bundling for packages
- Vite — UI packages (html-reporter, trace-viewer, recorder, dashboard)
- React / React-DOM — UI component rendering
2. System Requirements
2.1 Runtime Requirements
| Requirement | Minimum |
|---|---|
| Node.js | 18 or later |
| npm | 8+ (ships with Node 18+) |
| Disk space | ~500 MB per browser engine (Chromium, Firefox, WebKit) |
| RAM | 2 GB minimum for single browser; 4+ GB recommended for parallel execution |
2.2 Supported Platforms
Playwright supports these host platforms for running tests:
| OS | Architectures |
|---|---|
| Ubuntu 20.04, 22.04, 24.04 (and Debian derivatives) | x64, arm64 |
| macOS 13 (Ventura), 14 (Sonoma), 15 (Sequoia) | x64, arm64 (Apple Silicon) |
| Windows 10, 11, Server 2019, Server 2022 | x64 |
Important
Windows ARM64 support is not yet available (tracked in issue #40202). Ubuntu 26.04 support is tracked in issue #40117. The platform detection logic in
utils/will throw "Unsupported platform: ..." for unrecognized host platforms.
2.3 System Dependencies (Linux)
On Linux, browsers require system shared libraries. Use the built-in dependency installer:
# Install system dependencies for all browsers
npx playwright install-deps
# Install dependencies for a specific browser
npx playwright install-deps chromium
For Docker environments, Playwright provides pre-built images (see Section 4.3).
2.4 Browser Installation Paths
Browser binaries are stored at platform-specific default locations unless overridden:
| Platform | Default Path |
|---|---|
| Linux | $XDG_CACHE_HOME/ms-playwright (defaults to ~/.cache/ms-playwright) |
| macOS | ~/Library/Caches/ms-playwright |
| Windows | %LOCALAPPDATA%\ms-playwright |
Override with PLAYWRIGHT_BROWSERS_PATH:
# Store browsers in a shared directory
export PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
npx playwright install
3. Configuration Reference
3.1 Config File Resolution
Playwright looks for configuration in this order:
playwright.config.tsplaywright.config.jsplaywright.config.mjsplaywright.config.cjs
The config file location determines the default testDir (the directory containing the config file).
3.2 Top-Level Configuration Options
The FullConfigInternal constructor defines every valid top-level option. Below is the complete reference:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// --- Test Discovery ---
testDir: './tests', // Test directory (default: config file directory)
testMatch: '**/*.@(spec|test).?(c|m)[jt]s?(x)', // Test file pattern
testIgnore: undefined, // Glob patterns to ignore
// --- Execution Control ---
fullyParallel: false, // Run ALL tests in parallel (not just across files)
workers: '50%', // Number or percentage of CPU cores
retries: 0, // Retry count for failed tests
repeatEach: 1, // Repeat each test N times
maxFailures: 0, // Stop after N failures (0 = unlimited)
timeout: 30000, // Per-test timeout in ms
globalTimeout: 0, // Global timeout (0 = unlimited)
forbidOnly: false, // Fail CI if test.only is present
failOnFlakyTests: false, // Treat flaky tests as failures
// --- Filtering ---
grep: /.*/, // Filter tests by title regex
grepInvert: undefined, // Exclude tests matching regex
tag: undefined, // Global tags (must start with @)
// --- Output ---
outputDir: 'test-results', // Test artifacts directory
preserveOutput: 'always', // 'always' | 'never' | 'failures-only'
quiet: false, // Suppress stdio
reporter: [['list']], // Reporter configuration
reportSlowTests: { max: 5, threshold: 300000 }, // Slow test reporting
// --- Snapshots ---
updateSnapshots: 'missing', // 'all' | 'none' | 'missing'
updateSourceMethod: 'patch', // 'patch' | 'overwrite'
ignoreSnapshots: false, // Skip snapshot assertions
respectGitIgnore: true, // Honor .gitignore for snapshots
// --- Setup/Teardown ---
globalSetup: undefined, // Path(s) to global setup file
globalTeardown: undefined, // Path(s) to global teardown file
// --- Sharding ---
shard: undefined, // { current: N, total: M }
// --- Projects ---
projects: [], // Array of project configurations
// --- Web Server ---
webServer: undefined, // Auto-start server config (single or array)
// --- Metadata ---
metadata: {}, // Custom metadata object
captureGitInfo: false, // Capture git info in test metadata
// --- TypeScript ---
tsconfig: undefined, // Custom TypeScript config path
});
Important
The
workersoption accepts either a number (4) or a percentage string ('50%'). Passing an invalid value triggers the error: "Workers ... must be a number or percentage". In CI environments, percentage-based workers automatically scale to the available cores.
3.3 Project-Level Configuration
Projects allow running the same tests against different browsers or configurations:
export default defineConfig({
projects: [
{
name: 'chromium',
testDir: './tests',
testMatch: '**/*.spec.ts',
testIgnore: '**/mobile/**',
outputDir: 'test-results/chromium',
snapshotDir: './snapshots',
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
timeout: 30000,
retries: 2,
repeatEach: 1,
grep: /.*/,
grepInvert: undefined,
metadata: {},
fullyParallel: true,
ignoreSnapshots: false,
respectGitIgnore: true,
use: {
browserName: 'chromium',
headless: true,
viewport: { width: 1280, height: 720 },
},
dependencies: ['setup'], // Run 'setup' project first
teardown: 'cleanup', // Run 'cleanup' project after
},
{
name: 'setup',
testMatch: /global\.setup\.ts/,
},
{
name: 'cleanup',
testMatch: /global\.teardown\.ts/,
},
],
});
Dependency rules enforced by the config validator:
- A project listed in
dependenciesmust exist by name — "Project ... depends on unknown project ..." is thrown otherwise. - A teardown project must not itself declare dependencies — "Teardown project ... must not have dependencies" is the error for violations.
3.4 Reporter Configuration
Built-in reporters:
| Reporter | Output | Best For |
|---|---|---|
list |
Detailed per-test output | Local development (default for terminal) |
line |
One-line-per-test updates | Compact terminal output |
dot |
Dots for pass/fail | CI environments (default when CI env var is set) |
json |
JSON to stdout | Programmatic consumption |
junit |
JUnit XML | CI/CD integration (Jenkins, GitLab, etc.) |
html |
Interactive HTML report | Post-run analysis and sharing |
blob |
Binary blob | Merge sharded results |
github |
GitHub Actions annotations | GitHub Actions workflows |
null |
No output | Suppressing output entirely |
Multiple reporters can be active simultaneously:
reporter: [
['list'],
['junit', { outputFile: 'results.xml' }],
['html', { open: 'never' }],
],
3.5 Web Server Configuration
Auto-start a dev server before tests:
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
stdout: 'pipe',
stderr: 'pipe',
},
Multiple servers are supported by passing an array.
4. Deployment & Scaling
4.1 CI/CD Integration
Sharding across machines:
# Machine 1
npx playwright test --shard=1/4
# Machine 2
npx playwright test --shard=2/4
# Machine 3
npx playwright test --shard=3/4
# Machine 4
npx playwright test --shard=4/4
Merge sharded results using the blob reporter:
# Each shard produces a blob
npx playwright test --shard=1/4 --reporter=blob
# Merge all blobs into a single HTML report
npx playwright merge-reports --reporter=html ./blob-reports
Caching browser binaries in CI:
# Cache key based on Playwright version
PLAYWRIGHT_VERSION=$(npx playwright --version)
# Cache directory: $PLAYWRIGHT_BROWSERS_PATH or default location
# GitHub Actions example
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('package-lock.json') }}
Tip
Set
PLAYWRIGHT_BROWSERS_PATHto a directory within your CI cache path for reliable cache hits. Theinstall --dry-runcommand shows what would be installed without downloading, useful for verifying cache coverage.
4.2 Remote Browser Execution
Running a Playwright Server:
# Start a remote browser server
npx playwright run-server \
--port 3000 \
--host 0.0.0.0 \
--path /ws \
--max-clients 10 \
--mode default \
--artifacts-dir /tmp/pw-artifacts
Launching via config file:
# launch-config.json
{
"browser": "chromium",
"headless": true,
"port": 3000
}
npx playwright launch-server --config launch-config.json
Connecting from tests:
// Connect to a remote browser server
const browser = await chromium.connect('ws://remote-host:3000/ws');
Or via environment variables:
PW_TEST_CONNECT_WS_ENDPOINT=ws://remote-host:3000/ws npx playwright test
PW_TEST_CONNECT_HEADERS='{"Authorization":"Bearer token"}' npx playwright test
PW_TEST_CONNECT_EXPOSE_NETWORK="*" npx playwright test
4.3 Docker Deployment
Playwright provides Docker tooling in utils/docker/ for building images with pre-installed browsers and system dependencies.
Using the official Docker images:
FROM mcr.microsoft.com/playwright:v1.60.0-focal
WORKDIR /app
COPY package*.json ./
RUN npm ci
RUN npx playwright install --with-deps
COPY . .
CMD ["npx", "playwright", "test"]
Marking custom Docker images:
# Mark a Docker image so Playwright skips browser compatibility checks
npx playwright mark-docker-image
Tip
In Docker/CI environments, always use
--with-depsduringnpx playwright installto ensure system libraries are present. Without it, browsers will fail to launch with missing shared library errors.
4.4 Worker Scaling
The workers configuration controls parallelism:
// Fixed count
workers: 4,
// Percentage of available CPUs
workers: '50%',
// Single worker (serial execution)
workers: 1,
Scaling considerations:
- Each worker is a separate Node.js process running one or more browser instances
- Memory usage scales linearly with worker count — budget ~300-500 MB per worker with a single browser
- CPU-bound test suites benefit from worker counts up to the number of physical cores
- I/O-bound suites (network-heavy tests) can exceed core count effectively
- Set
fullyParallel: trueto parallelize tests within a single file across workers (default only parallelizes across files)
4.5 Browser Garbage Collection
Playwright automatically garbage-collects old browser versions. Control this behavior:
# Skip browser GC (useful in shared/cached environments)
export PLAYWRIGHT_SKIP_BROWSER_GC=1
npx playwright install
Use npx playwright install --list to see all installed browser versions across all Playwright installations on the system.
5. Operations
5.1 Browser Management
Installation commands:
# Install all browsers
npx playwright install
# Install specific browser
npx playwright install chromium
npx playwright install firefox
npx playwright install webkit
# Install with system dependencies (Linux)
npx playwright install --with-deps
# Dry run — show what would be installed
npx playwright install --dry-run
# List all installed browsers
npx playwright install --list
# Custom install path
PLAYWRIGHT_BROWSERS_PATH=/shared/browsers npx playwright install
Custom registry:
# Use a custom server for browser downloads (air-gapped environments)
export PLAYWRIGHT_SERVER_REGISTRY=https://internal-mirror.company.com/playwright
npx playwright install
Note
The
PLAYWRIGHT_SERVER_REGISTRYenvironment variable redirects all browser download requests to a custom URL. This is essential for air-gapped or restricted network environments. The registry must mirror the same directory structure as the default Playwright CDN.
5.2 Debugging Facilities
Playwright Inspector:
# Launch with Inspector attached
PWDEBUG=1 npx playwright test
# Pause at end of test
PWPAUSE=1 npx playwright test
Debug logging:
# Enable protocol-level debug output
DEBUG=pw:api npx playwright test
# Enable all Playwright debug output
DEBUG=pw:* npx playwright test
# Write debug output to a file
DEBUG=pw:* DEBUG_FILE=playwright-debug.log npx playwright test
Runner-level debugging:
# Enable test runner debug output
PW_RUNNER_DEBUG=1 npx playwright test
Trace recording:
# Enable tracing for all tests
PWTEST_TRACE=1 npx playwright test
# View a trace file
npx playwright show-trace trace.zip
5.3 Report Management
HTML reports:
# Generate and auto-open HTML report
npx playwright show-report
# Custom report title
PLAYWRIGHT_HTML_TITLE="Nightly Regression" npx playwright test --reporter=html
# Merge sharded reports
npx playwright merge-reports --reporter=html ./blob-reports
JUnit for CI:
npx playwright test --reporter=junit > results.xml
5.4 Codegen and Recording
# Record user actions and generate test code
npx playwright codegen https://example.com
# Open a specific browser for manual testing
npx playwright open --browser=firefox https://example.com
5.5 Driver Mode
For language bindings (Python, Java, C#, Go), Playwright provides a pipe-based driver:
# Start the driver (used by non-Node.js SDKs)
npx playwright run-driver
# Configure SDK language name
PW_LANG_NAME=python npx playwright run-driver
Note
The
run-drivercommand starts a JSON-RPC server over stdin/stdout pipes. The Python, Java, and C# Playwright SDKs use this to communicate with the Node.js server process.PW_LANG_NAMEcontrols which SDK-specific behaviors are activated in the server.
6. Performance
6.1 Test Execution Optimization
Parallelism tuning:
| Scenario | Recommended workers |
fullyParallel |
|---|---|---|
| Local dev, fast feedback | '50%' (default) |
false |
| CI with ample resources | Number of cores | true |
| CI with constrained RAM | 2-4 |
false |
| Debugging a single test | 1 |
false |
| Flake detection | 1 with repeatEach: 10 |
false |
Slow test detection:
The default reportSlowTests config flags tests exceeding 5 minutes (300,000 ms) and reports up to 5 of them. Adjust for your suite:
reportSlowTests: {
max: 10, // Report up to 10 slow tests
threshold: 60000, // Flag anything over 1 minute
},
6.2 Browser Context Reuse
For test suites where browser startup is a bottleneck:
# Reuse browser context across tests (experimental)
PW_TEST_REUSE_CONTEXT=1 npx playwright test
Caution
Context reuse skips browser context teardown between tests. This speeds up execution but means tests share cookies, localStorage, and other state. Only use this when tests are designed for shared state, or in combination with explicit cleanup in
beforeEachhooks.
6.3 Module Instrumentation
For diagnosing slow startup:
# Profile module loading times
PW_INSTRUMENT_MODULES=1 npx playwright test
This logs the time taken to load each module, helping identify slow require()/import() chains.
6.4 Snapshot Update Strategies
| Strategy | updateSnapshots |
Use Case |
|---|---|---|
| Add new only | 'missing' (default) |
Normal development |
| Regenerate all | 'all' |
After intentional visual changes |
| Strict match | 'none' |
CI — fail on any missing snapshot |
The updateSourceMethod option controls how test source files are modified when updating inline snapshots:
'patch'(default) — applies minimal diffs'overwrite'— replaces the entire file
7. Security
7.1 Threat Model
Playwright executes arbitrary web content in browser processes. The security boundary is:
Node.js process (trusted) → Protocol → Browser (sandboxed) → Web content (untrusted)
Key security considerations:
-
Browser sandbox — Playwright browsers run with their standard sandboxing. Chromium's multi-process sandbox, Firefox's content process isolation, and WebKit's WebProcess isolation all apply.
-
Injected scripts — Scripts from the
injectedpackage run in the browser's main world. They have access to the page DOM and JavaScript context. These scripts are trusted code injected by Playwright, not by the web page. -
Remote server access —
PlaywrightServerexposes browser automation over WebSocket. Anyone with network access to the server can control browsers, navigate to arbitrary URLs, and execute JavaScript.
Warning
The
run-servercommand with--host 0.0.0.0exposes browser automation to the network. There is no built-in authentication. Use network-level controls (firewalls, VPNs, private networks) to restrict access. In production grid setups, place the server behind an authenticating reverse proxy.
7.2 Sensitive Environment Variables
These variables carry credentials and should be treated as secrets in CI/CD:
| Variable | Contains |
|---|---|
PLAYWRIGHT_SERVICE_ACCESS_KEY |
Authentication key for Playwright hosted service |
PW_TEST_CONNECT_HEADERS |
Custom headers (may contain auth tokens) for remote connections |
Warning
Never log or echo
PLAYWRIGHT_SERVICE_ACCESS_KEYorPW_TEST_CONNECT_HEADERSin CI output. Use masked/secret variable features of your CI platform.
7.3 Network Exposure
webServer configuration — The webServer option starts a local development server. Ensure it binds only to localhost in CI environments to prevent unintended network exposure.
PW_TEST_CONNECT_EXPOSE_NETWORK — When connecting to a remote browser server, this variable controls which network targets the remote browser can access. Setting it to "*" grants access to all networks reachable from the server.
7.4 File System Access
Playwright writes to several directories:
| Directory | Contents | Sensitivity |
|---|---|---|
test-results/ (or outputDir) |
Screenshots, videos, traces, downloads | May contain application data |
| Browser cache directory | Browser binaries and profiles | Contains cached web data |
playwright-report/ |
HTML reports | May contain screenshots of application state |
| Trace files | Full DOM snapshots, network data, console logs | High — may contain PII or secrets visible in the application |
Caution
Trace files and HTML reports can contain sensitive application data including screenshots, network request/response bodies, cookies, and console output. Treat these artifacts with the same sensitivity as the application under test. Do not publish them to public storage without review.
7.5 TypeScript and Code Execution
Playwright's config file (playwright.config.ts) is executed as code. The test runner uses Node.js options for TypeScript support:
# Disable TypeScript ESM loader if it causes issues
PW_DISABLE_TS_ESM=1 npx playwright test
The NODE_OPTIONS environment variable is used internally to register the TypeScript loader. Be aware that overriding NODE_OPTIONS in your environment may interfere with Playwright's TypeScript support.
8. Developer Internals
8.1 Protocol Layer
The protocol package defines the complete wire protocol (~259K characters of type definitions). Communication between client and server uses JSON-RPC:
- Pipe transport — Used for in-process communication (default when launching browsers locally). The Node.js process communicates with the browser server over stdin/stdout pipes.
- WebSocket transport — Used for remote connections. The
PlaywrightServerhosts a WebSocket endpoint that accepts JSON-RPC messages.
8.2 Dispatcher System
The dispatcher hierarchy is the server-side counterpart to the client API. There are 25+ dispatcher classes:
Core dispatchers:
Dispatcher— base class with serialization, event emission, and lifecycle managementRootDispatcher— root of the dispatcher tree for a connectionDispatcherConnection— manages the full dispatcher tree and protocol message routingPlaywrightDispatcher— top-level dispatcher exposing browser types and devices
Browser lifecycle:
BrowserTypeDispatcher→BrowserDispatcher→BrowserContextDispatcher→PageDispatcher→FrameDispatcher→ElementHandleDispatcher
Supporting dispatchers:
CDPSessionDispatcher— raw CDP protocol access (Chromium only)- Plus dispatchers for Dialog, Download, Request, Response, Route, WebSocket, Worker, etc.
8.3 Injected Script System
The injected package contains scripts that run inside browser page contexts:
| Class | Purpose |
|---|---|
InjectedScript |
Main entry point — selector evaluation, element interaction, waiting |
SelectorEvaluatorImpl |
CSS and custom selector engine evaluation |
BindingsController |
Manages page bindings (exposing Node.js functions to the page) |
ClockController |
Fake timers and clock manipulation |
ConsoleAPI |
Console message interception |
Highlight |
Element highlighting for codegen and debugging |
StorageScript |
localStorage/sessionStorage manipulation |
UtilityScript |
Shared utilities for injected code |
WebSocketMock |
WebSocket interception and mocking |
These scripts are bundled at build time and injected via the protocol's evaluateExpression mechanism.
8.4 Selector Engine Architecture
The isomorphic package contains the selector parsing and evaluation infrastructure:
- CSS Parser —
CSSParserTokenwith 20+ token subclasses, handles the full CSS selector syntax - Selector Parser — Parses Playwright's extended selector syntax (
text=,css=,xpath=,role=, chained selectors with>>) - Locator Generators — Language-specific code generators that produce locator expressions:
JavaScriptLocatorFactoryPythonLocatorFactoryJavaLocatorFactoryCSharpLocatorFactory
These are used by the codegen recorder to produce test code in the target language.
8.5 Fixture System Internals
The FixtureRunner resolves a dependency graph of fixtures:
- Each
Fixtureinstance declares its dependencies (other fixtures it needs) - The runner topologically sorts the dependency graph
- Setup runs in dependency order; teardown runs in reverse
- Fixtures can be scoped to
test(per-test) orworker(per-worker process)
Error conditions:
- "Cannot provide fixture value for the second time" — a fixture's
use()callback was invoked more than once - "use() was not called in fixture ..." — a fixture function completed without calling the provided
use()function - "Playwright detected inconsistent test.use() options" — conflicting
use()declarations across test files sharing a worker
8.6 Shared Utilities
The utils package provides Node.js-level infrastructure:
| Module | Purpose |
|---|---|
comparators |
Image comparison (pixel diff, SSIM) |
crypto |
Hashing and random ID generation |
debug |
Debug logging (integrates with the debug npm package) |
env |
Environment variable reading and validation |
fileUtils |
File I/O helpers with atomic writes |
hostPlatform |
Host OS/architecture detection (overridable via PLAYWRIGHT_HOST_PLATFORM_OVERRIDE) |
profiler |
Performance measurement |
processLauncher |
Cross-platform process spawning with cleanup |
zones |
Async context tracking (Zone.js-like) |
The isomorphic package also provides:
LRUCache— least-recently-used cacheManualPromise— externally resolvable PromiseSemaphore— concurrency limiterMultiMap— map with multiple values per keyInvalidSelectorError— typed error for selector parsing failures
8.7 ARIA Snapshot System
The isomorphic package includes ARIA snapshot generation — a tree-based representation of the accessibility structure of a page. This powers the toMatchAriaSnapshot() assertion in the test runner.
9. Integration Points
9.1 Playwright Service
Playwright can connect to Microsoft's hosted service or a self-hosted equivalent:
PLAYWRIGHT_SERVICE_URL=https://playwright-service.example.com
PLAYWRIGHT_SERVICE_ACCESS_KEY=your-key
PLAYWRIGHT_SERVICE_RUN_ID=unique-run-id
PLAYWRIGHT_SERVICE_OS=linux # or windows
9.2 VS Code Extension
Playwright integrates with VS Code through the official extension. Known issue #40226 tracks cases where the extension fails to discover tests.
9.3 Component Testing
The component testing packages (playwright-ct-*) integrate with framework build tools:
// playwright-ct.config.ts
import { defineConfig } from '@playwright/experimental-ct-react';
export default defineConfig({
use: {
ctPort: 3100,
ctTemplateDir: './playwright',
},
});
The PLAYWRIGHT_TEST_BASE_URL environment variable overrides the component test server URL.
9.4 Dashboard
The dashboard package provides a UI for viewing test results. Enable via:
PLAYWRIGHT_DASHBOARD=1 npx playwright test
9.5 Custom Sockets Directory
For environments with restrictions on the default socket path:
PLAYWRIGHT_SOCKETS_DIR=/custom/path/sockets npx playwright test
10. Troubleshooting
10.1 Browser Launch Failures
Error: Unsupported browser ...
- Cause: Passed a browser name other than
chromium,firefox, orwebkit - Solution: Use one of the three supported browser names
- Prevention: Validate browser names in your config against the allowed set
Error: Directory does not exist: ...
- Cause: The configured
testDir,outputDir, or other path does not exist on disk - Solution: Create the directory or correct the path in
playwright.config.ts - Prevention: Use relative paths anchored to the config file location
Error: Browser fails to launch with missing shared library errors (Linux)
- Cause: System dependencies not installed
- Solution: Run
npx playwright install-depsor use the--with-depsflag - Prevention: Use Playwright Docker images or include
install-depsin your CI setup
Tip
The
npx playwright install --dry-runcommand shows exactly which browsers would be downloaded and their expected paths, without performing any downloads. Use this to verify your CI cache is correctly configured.
10.2 Configuration Errors
Error: Cannot use --browser option when configuration file defines projects
- Cause: The
--browserCLI flag conflicts with project-based configuration - Solution: Remove
--browserfrom the CLI and configure browsers inprojectsinstead - Prevention: Choose one approach — CLI flags for simple setups, projects for multi-browser
Error: Tag must start with @ symbol
- Cause: A tag in config or CLI does not begin with
@ - Solution: Prefix all tags with
@(e.g.,@smoke,@regression)
Error: Workers ... must be a number or percentage
- Cause: Invalid
workersvalue (e.g., a non-numeric string) - Solution: Use a positive integer or a percentage string like
'50%'
Error: Project ... depends on unknown project ...
- Cause: A
dependenciesentry references a project name that does not exist - Solution: Verify project names match exactly (case-sensitive)
Error: Teardown project ... must not have dependencies
- Cause: A project designated as
teardownalso declaresdependencies - Solution: Remove
dependenciesfrom the teardown project — it runs unconditionally after its parent
Note
The error "Playwright detected inconsistent test.use() options" occurs when tests in the same worker process declare different
use()options. Either move conflicting tests to separate projects or ensure consistentuse()declarations within each project.
10.3 Runtime Issues
Error: Unexpected browserName ..., must be one of chromium, firefox or webkit
- Cause: The
use.browserNameoption in config ortest.use()has a typo or invalid value - Solution: Set
browserNameto exactly'chromium','firefox', or'webkit'
Issue: Tests stuck at about:blank (GitHub #31050, 50+ comments)
- Cause: Navigation race conditions, especially with single-page apps
- Solution: Use
waitUntil: 'networkidle'or explicit waiting for application-specific elements rather than relying on default navigation completion
Issue: Proxy authentication hangs (GitHub #40194)
- Cause: Browser-level proxy auth dialogs are not automatically handled
- Solution: Provide proxy credentials in the proxy configuration object rather than relying on interactive authentication
Issue: Dialog handler not working as expected (GitHub #11014, 37 comments)
- Cause: Dialog handlers must be registered before the action that triggers the dialog
- Solution: Always call
page.on('dialog', handler)before the click or navigation that produces the dialog
Caution
The
--only-changedflag is not supported in UI mode. Attempting to use it produces: "--only-changed is not supported in UI mode". Use CLI mode for changed-file-only test execution.
10.4 Android Automation
Error: No devices found
- Cause: No Android device connected or ADB not configured
- Solution: Connect a device via USB with USB debugging enabled, or start an emulator
Error: More than one device found. Please specify deviceSerialNumber
- Cause: Multiple Android devices/emulators are connected
- Solution: Pass the
deviceSerialNumberoption to specify which device to use. List devices withadb devices.
10.5 WebKit-Specific Issues
- Issue #40268: WebKit WASM — WebAssembly-related failures in WebKit
- Issue #40244: WebKit
formData()— FormData parsing issues in WebKit
These are browser-engine-level issues tracked upstream in the Playwright patched WebKit build.
10.6 TypeScript Issues
Issue #38586: TypeScript declare keyword handling
- Certain TypeScript declaration patterns may not be recognized by Playwright's TypeScript loader
Disabling TypeScript ESM loader:
PW_DISABLE_TS_ESM=1 npx playwright test
Use this when the experimental TypeScript ESM loader conflicts with your project's module setup.
Appendix A: Complete Environment Variable Reference
| Variable | Purpose | Default |
|---|---|---|
PLAYWRIGHT_BROWSERS_PATH |
Custom browser installation directory | Platform default (see Section 2.4) |
PLAYWRIGHT_SKIP_BROWSER_GC |
Skip browser garbage collection | Not set |
PLAYWRIGHT_SERVER_REGISTRY |
Custom browser download registry URL | Official CDN |
PLAYWRIGHT_HOST_PLATFORM_OVERRIDE |
Override host platform detection | Auto-detected |
PLAYWRIGHT_SOCKETS_DIR |
Custom sockets directory | OS default |
PLAYWRIGHT_NO_COPY_PROMPT |
Disable copy prompt in CLI tools | Not set |
PLAYWRIGHT_HTML_TITLE |
Custom HTML report title | "Playwright Test Report" |
PLAYWRIGHT_DASHBOARD |
Enable dashboard binding | Not set |
PLAYWRIGHT_TEST_BASE_URL |
Base URL for component tests | Not set |
PLAYWRIGHT_SERVICE_URL |
Playwright service URL | Not set |
PLAYWRIGHT_SERVICE_ACCESS_KEY |
Playwright service auth key | Not set |
PLAYWRIGHT_SERVICE_RUN_ID |
Playwright service run ID | Not set |
PLAYWRIGHT_SERVICE_OS |
Playwright service OS | Not set |
PWDEBUG |
Enable Playwright Inspector (set to 1) |
Not set |
PWPAUSE |
Pause at test end | Not set |
PWTEST_MODE |
Test mode override | Not set |
PWTEST_TRACE |
Enable tracing in tests | Not set |
PW_CLI_DISPLAY_VERSION |
Override displayed CLI version | Package version |
PW_EXTENSION_MODE |
Enable extension mode | Not set |
PW_LANG_NAME |
SDK language name for driver | Not set |
PW_INSTRUMENT_MODULES |
Enable module load instrumentation | Not set |
PW_RUNNER_DEBUG |
Enable runner debug output | Not set |
PW_TEST_REUSE_CONTEXT |
Reuse browser context | Not set |
PW_TEST_CONNECT_WS_ENDPOINT |
WebSocket endpoint for remote connection | Not set |
PW_TEST_CONNECT_HEADERS |
Custom headers for remote connection | Not set |
PW_TEST_CONNECT_EXPOSE_NETWORK |
Expose network for remote connection | Not set |
PW_DISABLE_TS_ESM |
Disable TypeScript ESM loader | Not set |
DEBUG |
Debug namespace (uses debug npm package) |
Not set |
DEBUG_FILE |
Write debug output to file | Not set |
NODE_OPTIONS |
Node.js options (used for TS loader) | Not set |
XDG_CACHE_HOME |
XDG cache directory (Linux browser path) | ~/.cache |
LOCALAPPDATA |
Local app data (Windows browser path) | System default |
Appendix B: Key Source Locations
| Component | Path |
|---|---|
| Test runner entry | packages/playwright/ |
| Core automation | packages/playwright-core/ |
| Protocol definitions | packages/protocol/ |
| Injected scripts | packages/injected/ |
| Selector/locator utilities | packages/isomorphic/ |
| Node.js utilities | packages/utils/ |
| Dispatcher hierarchy | packages/playwright-core/src/server/dispatchers/ |
| Browser patches | browser_patches/ |
| Docker tooling | utils/docker/ |
| Build system | utils/build/build.js |
| HTML reporter UI | packages/html-reporter/ |
| Trace viewer UI | packages/trace-viewer/ |
| Codegen recorder UI | packages/recorder/ |