Playwright: Getting Started
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Playwright Test is the end-to-end test runner that ships with Playwright: it bundles the runner, the assertions, test isolation, parallelism and the tooling (HTML report, UI Mode, trace viewer, code generator) in one package. This page takes you from an empty folder to a running suite and then through every day-to-day command. It was written against Playwright 1.64.1 for Node.js (the Python, Java and .NET examples elsewhere in this section were run at 1.63) and checked on 25 October 2026. Every example that tests an application was run against the Bookshelf application, a small catalogue of books started on a local port; the scaffolding commands were run in an empty folder. For why Playwright works the way it does, see How Browser Automation Works; for choosing it over Cypress or Selenium, see Choosing a Tool.
System requirements
Playwright 1.64 documents these requirements:
| Item | Requirement |
|---|---|
Node.js |
The latest 22.x, 24.x or 26.x release. |
Windows |
Windows 11 or later, Windows Server 2019 or later, or Windows Subsystem for Linux (WSL). |
macOS |
macOS 14 (Sonoma) or later. |
Linux |
Debian 12 or 13, Ubuntu 22.04, 24.04 or 26.04, on x86-64 or arm64. |
Playwright runs Chromium, WebKit and Firefox on Windows, Linux and macOS, locally or in CI, headless or headed. It also offers native mobile emulation for Chrome on Android and Mobile Safari. The browsers are not the ones installed on your machine: each Playwright version downloads the exact builds it was tested with, so a test behaves the same on a laptop and in CI. 1.64 ships Chromium 156, Firefox 157 and WebKit 27.2.
Support for an operating system version is dropped from time to time: release 1.59 removed WebKit support for macOS 14 and release 1.61 added Ubuntu 26.04, so re-check the requirements when you upgrade the operating system or Playwright.
Installing Playwright
Scaffolding with npm init playwright@latest
The command below either initialises a new project or adds Playwright to an existing one. It is a thin wrapper around the
create-playwright package, so yarn create playwright and pnpm create playwright do the same.
mkdir bookshelf-e2e && cd bookshelf-e2e
npm init playwright@latest
Source: Playwright — Installation
Run interactively, it asks four questions:
-
TypeScript or JavaScript (the default is TypeScript).
-
The name of the tests folder (
tests, ore2eiftestsalready exists). -
Whether to add a GitHub Actions workflow (recommended when you run tests in CI).
-
Whether to install the Playwright browsers (the default is yes).
You can re-run the command later; it does not overwrite existing tests. For scripts and CI the same choices are flags:
| Flag | Effect |
|---|---|
|
Do not ask any question; use the defaults and the other flags. |
|
Language of the generated config and example test. |
|
Browsers to put in the default config. Without it the config lists |
|
Do not download browsers; run |
|
Do not create the example test files. |
|
Also install the operating system packages the browsers need (Linux). |
|
Add a GitHub Actions workflow. |
|
Install the |
|
Install Playwright component testing (see Component Testing). |
This run, in an empty folder, created a TypeScript project with a single browser:
npm init playwright@latest -- --quiet --lang=TypeScript --browser=chromium
Writing playwright.config.ts.
Writing tests/example.spec.ts.
Writing package.json.
Downloading browsers (npx playwright install chromium)…
✔ Success! Created a Playwright Test project at .../ex-getting-started-init
Inside that directory, you can run several commands:
npx playwright test
Runs the end-to-end tests.
npx playwright test --ui
Starts the interactive UI mode.
npx playwright test --project=chromium
Runs the tests only on Desktop Chrome.
npx playwright test example
Runs the tests in a specific file.
npx playwright test --debug
Runs the tests in debug mode.
npx playwright codegen
Auto generate tests with Codegen.
Source: Playwright — Installation
What is installed
The scaffold is small:
playwright.config.ts # test configuration
package.json # @playwright/test and @types/node as devDependencies
package-lock.json
.gitignore # node_modules, test-results, playwright-report, blob-report, playwright/.auth
tests/
example.spec.ts # a minimal starter test
In an existing project Playwright adds its dependencies to the current package.json. The generated package.json
lists @playwright/test with a caret range (^1.64.1 here) and @types/node. Pin the exact version
(npm install -D --save-exact @playwright/test@1.64.1) if you want builds that are reproducible between a laptop and CI
months apart, because every Playwright release changes the browser builds it expects.
The generated configuration, with its explanatory comments and commented-out examples removed, was:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
Each setting has a reason:
-
testDiris where Playwright looks for*.spec.tsand*.test.tsfiles. -
fullyParallel: trueruns the tests of one file in parallel too, not just different files. -
forbidOnlymakes the run fail in CI if someone committedtest.only. -
retriesis 2 in CI and 0 locally, so a flaky test is reported as "flaky" instead of hiding. -
workersis left to the default locally (half of the logical CPU cores) and set to 1 in CI. -
reporter: 'html'writes the report described in The HTML report. -
trace: 'on-first-retry'records a trace when a test is retried. -
projectsis the list of browser configurations. Without--browserthe scaffold lists Chromium, Firefox and WebKit.
All of these are explained in
Configuration, Fixtures & Projects. The server that
the tests talk to is not part of the scaffold; for Bookshelf the layout in
Example Application & Test Layout adds baseURL and
testIdAttribute to the use block.
Installing browsers
npm init playwright@latest runs npx playwright install for you. You run it yourself when you skipped that step, when
you upgrade Playwright (each version needs its own browser builds) and in CI.
npx playwright install # the default browsers
npx playwright install chromium # only Chromium
npx playwright install chromium webkit # a selection
npx playwright install --with-deps # browsers plus operating system packages
npx playwright install --help # all the browsers that can be installed
The options of playwright install:
| Option | Effect |
|---|---|
|
Install the system dependencies of the browsers too (Linux packages through |
|
Do not install; print what would be installed and where. |
|
Print the browsers of every Playwright installation on the machine. |
|
Reinstall browsers that are already installed. |
|
Install only |
|
Do not install |
|
Hide the download progress bars (useful in CI logs). |
|
Keep browsers that the current version no longer uses. |
npx playwright uninstall removes the browsers of the current installation, and npx playwright clear-cache clears
Playwright’s caches. A dry run shows what Playwright 1.64.1 downloads for the platform:
npx playwright install --dry-run
Chrome for Testing 156.0.8078.4 (playwright chromium v1248) Install location: ~/Library/Caches/ms-playwright/chromium-1248 Download url: https://cdn.playwright.dev/builds/cft/156.0.8078.4/mac-arm64/chrome-mac-arm64.zip Chrome Headless Shell 156.0.8078.4 (playwright chromium-headless-shell v1248) Install location: ~/Library/Caches/ms-playwright/chromium_headless_shell-1248 ... Firefox 157.0 (playwright firefox v1555) Install location: ~/Library/Caches/ms-playwright/firefox-1555 ... WebKit 27.2 (playwright webkit v2370) Install location: ~/Library/Caches/ms-playwright/webkit-2370 ... FFmpeg (playwright ffmpeg v1013) Install location: ~/Library/Caches/ms-playwright/ffmpeg-1013 ...
Source: Playwright — Browsers
Since release 1.57 Playwright uses Chrome for Testing builds instead of Chromium: headed mode runs chrome and headless
mode runs chrome-headless-shell, which is why both are downloaded. The browsers occupy a few hundred megabytes each;
PLAYWRIGHT_BROWSERS_PATH moves them to another folder (set it for both install and test). Behind a proxy, set
HTTPS_PROXY; with an internal artifact repository, set PLAYWRIGHT_DOWNLOAD_HOST (or the per-browser
PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST, PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST, PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST); and when a
download stalls, raise the idle timeout with PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT (milliseconds, default 30 seconds).
Playwright can also drive an installed Google Chrome or Microsoft Edge through the channel option; npx playwright install
msedge installs Edge, and it overwrites an existing installation at the default system location.
System dependencies on Linux
A freshly installed Linux machine or container usually lacks the shared libraries the browsers need (fonts, GTK, audio and
so on). install-deps installs them with the system package manager and asks for sudo:
npx playwright install-deps # dependencies of all browsers
npx playwright install-deps chromium # dependencies of one browser
npx playwright install --with-deps chromium # browsers and dependencies in one command
npx playwright install-deps --dry-run # simulate; on Linux exits non-zero if packages are missing
install-deps --dry-run does not change the system, which makes it usable in a verification script. On Windows it prints
the install command; on macOS and Windows the browsers bring what they need. Behind a proxy on Linux run the command as root
(sudo HTTPS_PROXY=... npx playwright install-deps), otherwise Playwright elevates itself and the variable does not reach
the package manager. The install-deps step was not run on this macOS host because it applies to Linux only.
Your first test
The scaffold’s tests/example.spec.ts tests the Playwright website, which is fine to see a green run but proves nothing
about your own application. This version of it tests Bookshelf. It needs no configuration beyond a baseURL, so page.goto('/')
resolves against the running server.
import { test, expect } from '@playwright/test';
test('home page has a title and a search form', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Bookshelf/);
await expect(page.getByTestId('search-input')).toBeVisible();
});
test('search narrows the catalogue to one book', async ({ page }) => {
await page.goto('/books');
await page.getByTestId('search-input').fill('quiet');
await page.getByRole('button', { name: 'Search' }).click();
await expect(page.getByTestId('book-card')).toHaveCount(1);
await expect(page.getByRole('heading', { name: 'The Quiet Compiler' })).toBeVisible();
});
The configuration used to run these examples:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: '.',
outputDir: './test-results',
reporter: [['list'], ['html', { outputFolder: './playwright-report', open: 'never' }]],
use: {
baseURL: process.env.BASE_URL,
testIdAttribute: 'data-testid',
trace: 'on-first-retry',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});
Source: Playwright — Test configuration
A test is a function passed to test(). Its argument is an object of fixtures: page is a new page in a new browser
context, created for this test and discarded afterwards. The body performs actions and asserts the state, and nothing in it
waits explicitly. Section Writing tests explains the pieces.
Writing tests
Navigation
Most tests start with page.goto(). A relative URL is resolved against baseURL; an absolute URL is used as is. Playwright
waits for the page to reach the load state before it continues. goto accepts waitUntil (load, domcontentloaded,
networkidle, commit), timeout and referer for the cases where load is the wrong signal, for example a page that
keeps a connection open.
await page.goto('/books?q=quiet');
await page.goto('/books/3', { waitUntil: 'domcontentloaded' });
Actions
Actions start with a locator, a description of how to find an element that Playwright evaluates again each time it is used. Before it acts, Playwright waits for the element to be actionable (attached, visible, stable, enabled and able to receive events), so a test needs no sleeps and does not race the page. The most used actions:
| Action | Description |
|---|---|
|
Click the element. |
|
Fill a form field with text. |
|
Check or uncheck a checkbox or radio button. |
|
Select an option in a drop-down. |
|
Press a single key. |
|
Hover the mouse over the element or focus it. |
|
Pick files to upload. |
The complete list of locators and actions, with the actionability rules, is in Locators, Actions & Auto-Waiting.
Assertions
expect(value) plus a matcher states what must be true. Matchers that take a locator or a page are web-first: they retry
until the condition holds or the assertion timeout (5 seconds by default) expires. They need await. The popular ones:
| Assertion | Description |
|---|---|
|
The element is visible. |
|
The control is enabled or checked. |
|
The text matches exactly or contains the value. |
|
The element has the attribute or the input has the value. |
|
A list of elements has the given length. |
|
The page has the given title or URL. |
Generic matchers such as toEqual, toContain and toBeTruthy check a value that already exists, so they are synchronous
and take no await. Using expect(await locator.isVisible()).toBe(true) instead of a web-first matcher throws the retry
away and is the usual source of flaky tests. See Assertions.
Test isolation
Each test gets its own browser context, the equivalent of a brand new browser profile with its own cookies, local storage and session storage, even when many tests share one browser process. The two tests below pass in any order because the second starts with empty storage, whichever worker runs it.
import { test, expect } from '@playwright/test';
test('dark theme is stored in this test only', async ({ page }) => {
await page.goto('/');
await page.getByTestId('theme-toggle').click();
const stored = await page.evaluate(() => localStorage.getItem('theme'));
expect(stored).not.toBeNull();
});
test('a second test starts with empty local storage', async ({ page }) => {
await page.goto('/');
const stored = await page.evaluate(() => localStorage.getItem('theme'));
expect(stored).toBeNull();
});
Isolation covers the browser, not the server. State on the server (the Bookshelf reviews, for example) is shared, which is why the examples reset it through the test API; see Test Design & Page Objects and Authentication & Isolation.
Test hooks
test.describe() groups tests. test.beforeEach() and test.afterEach() run around every test of the group;
test.beforeAll() and test.afterAll() run once per worker. Hooks receive the same fixtures as tests, except that
beforeAll and afterAll cannot use page (it is per test) but can use request and browser.
import { test, expect } from '@playwright/test';
test.describe('catalogue', () => {
test.beforeAll(async ({ request }) => {
// Once per worker: restore the 24 seeded books.
await request.post('/api/test/reset');
});
test.beforeEach(async ({ page }) => {
// Before every test: start on the first page of the catalogue.
await page.goto('/books');
});
test('shows six books per page', async ({ page }) => {
await expect(page.getByTestId('book-card')).toHaveCount(6);
});
test('next page changes the indicator', async ({ page }) => {
await page.getByTestId('page-next').click();
await expect(page).toHaveURL(/page=2/);
await expect(page.getByTestId('page-indicator')).toContainText('2');
});
test.afterEach(async ({ page }, testInfo) => {
console.log(`${testInfo.title}: ${testInfo.status}`);
});
});
In a real suite prefer fixtures to beforeEach for shared set-up, because a fixture runs only for the tests that ask for it
and cleans up after itself; see
Configuration, Fixtures & Projects.
Tags in tests
A test can carry tags, either as @name in its title or in the tag option (a string or an array). The command line
selects them with --grep. The tag in the tag option is not part of the title, but --grep matches it.
import { test, expect } from '@playwright/test';
test('catalogue lists books @smoke', async ({ page }) => {
await page.goto('/books');
await expect(page.getByTestId('book-list')).toBeVisible();
});
test('book detail shows a cover', { tag: '@detail' }, async ({ page }) => {
await page.goto('/books/1');
await expect(page.getByTestId('book-cover')).toBeVisible();
});
test('add a review needs a session', async ({ page }) => {
await page.goto('/books/1');
await expect(page.getByTestId('review-form')).toHaveCount(0);
});
Running tests
The command
Bookshelf was started on port 3911 and the tests received its address through BASE_URL. The config in this page has no
webServer entry; a project that starts its server from the config (as the example layout page does) needs neither.
BASE_URL=http://localhost:3911 npx playwright test
Running the five spec files above on both projects gave this:
Running 18 tests using 5 workers ✓ 4 [chromium] › first-test.spec.ts:3:5 › home page has a title and a search form (123ms) ✓ 7 [chromium] › first-test.spec.ts:10:5 › search narrows the catalogue to one book (183ms) ✓ 5 [chromium] › hooks.spec.ts:14:7 › catalogue › shows six books per page (113ms) ✓ 1 [chromium] › isolation.spec.ts:3:5 › dark theme is stored in this test only (149ms) ✓ 3 [chromium] › tagged.spec.ts:3:5 › catalogue lists books @smoke (114ms) ✓ 2 [webkit] › first-test.spec.ts:3:5 › home page has a title and a search form (445ms) ... 18 passed (2.1s)
By default tests run headless and in parallel, across the projects of the config, and the terminal shows the list
reporter locally and the dot reporter in CI. The scaffold’s own example (against the Playwright website) gave
2 passed (768ms) in Chromium.
Selecting what to run
Positional arguments are regular expressions matched against the full path of the test file. file:line selects the test
that starts at that line.
npx playwright test tests/todo-page/ tests/landing-page/ # directories
npx playwright test landing login # files whose path contains landing or login
npx playwright test first-test.spec.ts:10 # the test declared at line 10
npx playwright test --project=chromium # one project (repeat the flag for several)
npx playwright test --project webkit --project chromium
npx playwright test -g "add a review" # titles matching a regular expression
npx playwright test -g @smoke # tests tagged @smoke
npx playwright test --grep-invert "@smoke|@detail" # everything else
npx playwright test --list # collect and print, do not run
The commands against Bookshelf behaved as follows:
$ npx playwright test --project=chromium -g @smoke Running 1 test using 1 worker ✓ 1 [chromium] › tagged.spec.ts:3:5 › catalogue lists books @smoke (73ms) 1 passed (403ms) $ npx playwright test first-test.spec.ts:10 --project=chromium Running 1 test using 1 worker ✓ 1 [chromium] › first-test.spec.ts:10:5 › search narrows the catalogue to one book (139ms) 1 passed (419ms) $ npx playwright test hooks isolation --project=webkit --workers=1 --reporter=dot Running 4 tests using 1 worker ···· 4 passed (1.1s) $ npx playwright test --list --project=chromium Listing tests: [chromium] › first-test.spec.ts:3:5 › home page has a title and a search form [chromium] › first-test.spec.ts:10:5 › search narrows the catalogue to one book [chromium] › hooks.spec.ts:14:7 › catalogue › shows six books per page ... Total: 9 tests in 5 files
Two details: a title matched by -g also matches a tag given in the tag option, and a file filter such as hooks is a
regular expression, so escape special symbols such as $ or * and quote the argument in a shell.
Command line options
npx playwright test --help is the authoritative list. The ones used most:
| Option | Effect |
|---|---|
|
Run in headed browsers (the default is headless). |
|
Only run these projects; supports a |
|
Only run tests whose title (or tag) matches. |
|
Only run tests that do not match. |
|
Number of concurrent workers, or a percentage of the logical CPU cores. |
|
Run all tests in parallel, including those in one file. |
|
Open UI Mode. |
|
Run with the Playwright Inspector. A shortcut for |
|
Replace the configured reporters. Comma separated: |
|
Add reporters on top of those in the config instead of replacing them. |
|
Re-run only the tests that failed in the last run. |
|
Where the failed tests are stored (default |
|
Maximum retries for failing tests. |
|
Run each test |
|
Stop after the first (or |
|
Test timeout (default 30 seconds; 0 for none). |
|
Force a trace mode: |
|
Run one slice of the suite, for example |
|
Run in random order; the seed is printed so a failing order can be reproduced. |
|
Run only test files changed since |
|
Run (or skip) the tests listed in a file. |
|
Update screenshot and snapshot baselines. |
|
Fail the run if |
|
Succeed even when no tests are found. |
|
Maximum time for the whole run. |
|
Configuration file, or a folder that contains |
|
Folder for test artifacts (default |
|
One tsconfig for all imported files. |
Parallelism, sharding and retries have their own page, Parallelism, Sharding & Retries.
Re-running failures
After a failing run, --last-failed runs only what failed. A deliberate failing test was added for this demonstration:
npx playwright test --project=chromium # one test fails
cat test-results/.last-run.json
npx playwright test --project=chromium --last-failed
{
"status": "failed",
"failedTests": [
"8cd190df4f1066666642-efdf0e18fe1dbbbd309b"
]
}
Running 1 test using 1 worker
[1/1] [chromium] › failing.spec.ts:2:5 › deliberate failure
1) [chromium] › failing.spec.ts:2:5 › deliberate failure ──────────────────────
Error: expect(locator).toBeVisible() failed
Locator: getByRole('heading', { name: 'No such heading' })
Expected: visible
Timeout: 1000ms
Error: element(s) not found
In a sharded CI job give each shard its own file (--last-failed-file=.cache/last-run-shard-1.json) so the shards do not
overwrite each other’s list.
Headless and headed
Headless is the default: no window opens and the results appear in the terminal. It is what CI uses, it is faster and it works on machines without a display. Headed mode shows the browser window, which is the quickest way to see what a test does while you are writing it.
npx playwright test --headed
npx playwright test --headed --project=chromium --workers=1 first-test.spec.ts
Headed can also be set in the configuration (use: { headless: false }) or per context, but the command line flag leaves the
configuration untouched. A few practical differences:
-
Tests run in parallel, so several windows open at once; add
--workers=1to watch one test at a time. -
Headless uses the
chrome-headless-shellbuild and headed uses full Chrome for Testing (since 1.57); the behaviour is meant to be identical, and a difference is a Playwright bug worth reporting. -
In headless mode the clipboard is isolated from the operating system (release 1.62), so tests that use
navigator.clipboardno longer read or overwrite the clipboard of the machine. -
For debugging, prefer UI Mode or the Inspector to a plain headed run, because they let you step.
The headed examples above were not run: they open browser windows on the desktop, and the other commands in this page ran headless. Screenshots, videos and traces, which capture what headed mode shows, are covered in Screenshots, Videos & Traces.
UI Mode and the Inspector
npx playwright test --ui opens UI Mode, a window with the test tree, a watch mode, a timeline with "time travel" through
every step, DOM snapshots, the network log and a locator picker. npx playwright test --debug opens the Playwright Inspector
and a headed browser and lets you step through the API calls. Both are explained in
Debugging, Tracing & Codegen. They need a display, so they
were not run for this page.
npx playwright test --ui
npx playwright test --debug
npx playwright test first-test.spec.ts:10 --debug
The HTML report
The HTML reporter writes a self-contained folder, playwright-report, that you open as a web page: filter by browser,
passed, failed, skipped or flaky, search by title, open a test to see its error, steps, attachments and (for the first
retry) its trace. Since 1.57 a Speedboard tab sorts the executed tests by duration.
The html reporter is the default in the scaffold, and you can ask for it from the command line:
npx playwright test --reporter=html
npx playwright show-report # open the latest report
npx playwright show-report playwright-report/ # open a specific folder
npx playwright show-report --host 0.0.0.0 --port 8080
By default the report opens in the browser automatically only when a test failed (open: 'on-failure'). The option and
environment variables that control it:
| Reporter option | Environment variable | Meaning | Default |
|---|---|---|---|
|
|
When to open the report: |
|
|
|
Where the report is written. |
|
|
|
Host the report is served on when it opens. |
|
|
|
Port the report is served on. |
|
|
|
Title shown in the report. |
none |
|
|
Where the |
|
|
|
Write JavaScript, CSS and data as separate files for sites with a strict Content Security Policy. |
|
import { defineConfig } from '@playwright/test';
export default defineConfig({
reporter: [['html', { open: 'never', outputFolder: 'my-report' }]],
});
Do not rely on the automatic opening in CI: with open: 'on-failure' a failing CI run waits for Ctrl+C because the report
server keeps running. Set open: 'never' there (or the environment variable) and upload the folder as an artifact.
show-report also accepts a .zip archive, for example one downloaded from CI, as long as it contains index.html at its
top level (release 1.60). Serving the report from this run on a chosen host and port:
npx playwright show-report --host 127.0.0.1 --port 9411
Serving HTML report at http://127.0.0.1:9411. Press Ctrl+C to quit.
The server answered with HTTP 200 on that address. Other reporters (list, line, dot, json, junit, github,
blob) and merging blob reports from shards are covered in
Parallelism, Sharding & Retries and
Running in CI/CD.
The VS Code extension
The official Playwright extension for Visual Studio Code (identifier ms-playwright.playwright) lets you create, run, debug
and record tests without leaving the editor. It needs Node.js and VS Code. This page documents it from the official guide;
it was not exercised here because it needs the VS Code graphical interface.
-
Open the Extensions view (
Ctrl+Shift+XorCmd+Shift+X), search for "Playwright" and install the extension from Microsoft. -
Open the Command Palette (
Ctrl+Shift+PorCmd+Shift+P) and run Test: Install Playwright. -
Choose the browsers, and optionally add a GitHub Actions workflow. You can change this later in
playwright.config.ts. -
Open the Testing icon in the Activity Bar to see the Test Explorer and the Playwright sidebar.
What it offers:
| Task | How |
|---|---|
Run tests |
Click the green triangle next to a test, a file or the whole project. Results show beside the test and in the Test Results panel. |
Run on several browsers |
Check the projects in the Playwright sidebar. Each project is a browser configuration from the config file; the first one is selected by default. |
Watch the browser |
Enable Show Browsers in the sidebar. Disable it to run headless. |
Debug |
Set a breakpoint, right-click the test and choose Debug Test. With Show Browsers enabled, clicking a locator in the code highlights the element in the page. |
Trace Viewer |
Enable Show Trace Viewer; a trace opens when the test finishes. |
Fix a failure with AI |
Click the sparkle icon beside the error to ask Copilot for a suggested fix. |
Record a test |
Record new opens a browser and writes code as you click; Record at cursor inserts actions at the cursor; Pick locator copies the best locator for an element. |
Setup and global setup |
Project dependency tests appear in the Test Explorer and can run on their own; global setup and teardown can be triggered from the sidebar. |
Several configurations |
Switch between |
Source: Playwright — VS Code
The extension runs the same runner as the command line, so anything that works in the terminal works there, and a
test that is flaky in one place is flaky in the other. The recording and locator-picking features are the same as
the codegen command described in
Debugging, Tracing & Codegen.
Canary releases
Playwright for Node.js publishes a canary release every day under the next npm dist tag, for any code-related commit on the
main branch. It lets you try an unreleased feature, or confirm that a bug is fixed, before the next stable version, and it is
a good way to give feedback to the maintainers. The npm tags at the check date:
npm view @playwright/test dist-tags --json
{
"rc": "1.18.0-rc1",
"latest": "1.64.1",
"beta": "1.64.1-beta-1792067398000",
"next": "1.65.0-alpha-2026-10-25"
}
-
latestis the stable release. -
nextis the daily canary. -
betais published after a release branch is cut, usually a week before a stable release, for each commit.
npm install -D @playwright/test@next
npm init playwright@latest -- --next # scaffold a project on the next tag
npx playwright install # the canary may need newer browser builds
Source: Playwright — Canary releases
The Playwright maintainers state that a canary passes all automated tests and is used to test the HTML report, the trace
viewer and the Inspector, but it can still change from day to day, so do not rely on it for a production build; pin
latest there. The documentation for the next version is published on playwright.dev as well: press Shift five times on the
site to switch to it. The canary install was not run so that the shared test project kept its pinned 1.64.1.
Common pitfalls
-
Forgetting to install browsers after an upgrade. The error message says the executable does not exist and tells you to run
npx playwright install. -
Running as a different user than the one who installed the browsers. Browsers are stored per user (for example
~/Library/Caches/ms-playwright); setPLAYWRIGHT_BROWSERS_PATHto share them. -
Missing Linux libraries. Use
npx playwright install --with-depsor the Playwright Docker image (mcr.microsoft.com/playwright:v1.64.1-noble), whose version tag must match the installed Playwright. -
Using the system Chrome without a channel. Tests use Playwright’s own build unless you set
channel: 'chrome'. -
Waiting for the report in CI. See the HTML report section above.
-
Quoting. Regular expressions in
-gand file filters need quotes in a shell, and|inside them is a pipe otherwise. -
Local Firefox on a new operating system. On the macOS 27 host used for these pages the Firefox build 1555 failed to launch ("Could not find profile folder"), while the same build worked in the Linux Docker image. If a browser fails to start locally, try the container before concluding the tests are wrong.
What changed recently
-
1.64 (October 2026): browsers Chromium 156, Firefox 157, WebKit 27.2; new
--shuffle [seed]command line option to run in random order and reproduce an order from its seed. -
1.63:
--add-reporterappends reporters instead of replacing the configured ones;omitTagsfor the text reporters. -
1.62: the clipboard is isolated from the operating system in headless mode.
-
1.61: Ubuntu 26.04 supported.
-
1.60:
show-reportaccepts.ziparchives. -
1.59:
npx playwright test --debug=clilets coding agents attach and debug overplaywright-cli; WebKit support for macOS 14 removed. -
1.57: Chrome for Testing builds replace Chromium (headed runs
chrome, headless runschrome-headless-shell); the HTML report gains a Speedboard tab. Docker images moved from Node.js 22 to 24. -
1.44 and 1.46:
--last-failedand--only-changedwere introduced.
Source: Playwright — Release notes