Skip to main content

Release notes

Version 1.52

Highlights

  • New method expect(locator).toContainClass() to ergonomically assert individual class names on the element.

    await expect(page.getByRole('listitem', { name: 'Ship v1.52' })).toContainClass('done');
  • Aria Snapshots got two new properties: /children for strict matching and /url for links.

    await expect(locator).toMatchAriaSnapshot(`
    - list
    - /children: equal
    - listitem: Feature A
    - listitem:
    - link "Feature B":
    - /url: "https://playwright.dev"
    `);

Test Runner

  • New property testProject.workers allows to specify the number of concurrent worker processes to use for a test project. The global limit of property testConfig.workers still applies.
  • New testConfig.failOnFlakyTests option to fail the test run if any flaky tests are detected, similarly to --fail-on-flaky-tests. This is useful for CI/CD environments where you want to ensure that all tests are stable before deploying.
  • New property testResult.annotations contains annotations for each test retry.

Miscellaneous

  • New option maxRedirects in apiRequest.newContext() to control the maximum number of redirects.
  • New option ref in locator.ariaSnapshot() to generate reference for each element in the snapshot which can later be used to locate the element.
  • HTML reporter now supports NOT filtering via !@my-tag or !my-file.spec.ts or !p:my-project.

Breaking Changes

  • Glob URL patterns in methods like page.route() do not support ? and [] anymore. We recommend using regular expressions instead.
  • Method route.continue() does not allow to override the Cookie header anymore. If a Cookie header is provided, it will be ignored, and the cookie will be loaded from the browser's cookie store. To set custom cookies, use browserContext.addCookies().
  • macOS 13 is now deprecated and will no longer receive WebKit updates. Please upgrade to a more recent macOS version to continue benefiting from the latest WebKit improvements.

Browser Versions

  • Chromium 136.0.7103.25
  • Mozilla Firefox 137.0
  • WebKit 18.4

This version was also tested against the following stable channels:

  • Google Chrome 135
  • Microsoft Edge 135

Version 1.51

StorageState for indexedDB

  • New option indexedDB for browserContext.storageState() allows to save and restore IndexedDB contents. Useful when your application uses IndexedDB API to store authentication tokens, like Firebase Authentication.

    Here is an example following the authentication guide:

    tests/auth.setup.ts
    import { test as setup, expect } from '@playwright/test';
    import path from 'path';

    const authFile = path.join(__dirname, '../playwright/.auth/user.json');

    setup('authenticate', async ({ page }) => {
    await page.goto('/');
    // ... perform authentication steps ...

    // make sure to save indexedDB
    await page.context().storageState({ path: authFile, indexedDB: true });
    });

Copy as prompt

New "Copy prompt" button on errors in the HTML report, trace viewer and UI mode. Click to copy a pre-filled LLM prompt that contains the error message and useful context for fixing the error.

Copy prompt

Filter visible elements

New option visible for locator.filter() allows matching only visible elements.

example.spec.ts
test('some test', async ({ page }) => {
// Ignore invisible todo items.
const todoItems = page.getByTestId('todo-item').filter({ visible: true });
// Check there are exactly 3 visible ones.
await expect(todoItems).toHaveCount(3);
});

Git information in HTML report

Set option testConfig.captureGitInfo to capture git information into testConfig.metadata.

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
captureGitInfo: { commit: true, diff: true }
});

HTML report will show this information when available:

Git information in the report

Test Step improvements

A new TestStepInfo object is now available in test steps. You can add step attachments or skip the step under some conditions.

test('some test', async ({ page, isMobile }) => {
// Note the new "step" argument:
await test.step('here is my step', async step => {
step.skip(isMobile, 'not relevant on mobile layouts');

// ...
await step.attach('my attachment', { body: 'some text' });
// ...
});
});

Miscellaneous

Browser Versions

  • Chromium 134.0.6998.35
  • Mozilla Firefox 135.0
  • WebKit 18.4

This version was also tested against the following stable channels:

  • Google Chrome 133
  • Microsoft Edge 133

Version 1.50

Test runner

  • New option timeout allows specifying a maximum run time for an individual test step. A timed-out step will fail the execution of the test.

    test('some test', async ({ page }) => {
    await test.step('a step', async () => {
    // This step can time out separately from the test
    }, { timeout: 1000 });
    });
  • New method test.step.skip() to disable execution of a test step.

    test('some test', async ({ page }) => {
    await test.step('before running step', async () => {
    // Normal step
    });

    await test.step.skip('not yet ready', async () => {
    // This step is skipped
    });

    await test.step('after running step', async () => {
    // This step still runs even though the previous one was skipped
    });
    });
  • Expanded expect(locator).toMatchAriaSnapshot() to allow storing of aria snapshots in separate YAML files.

  • Added method expect(locator).toHaveAccessibleErrorMessage() to assert the Locator points to an element with a given aria errormessage.

  • Option testConfig.updateSnapshots added the configuration enum changed. changed updates only the snapshots that have changed, whereas all now updates all snapshots, regardless of whether there are any differences.

  • New option testConfig.updateSourceMethod defines the way source code is updated when testConfig.updateSnapshots is configured. Added overwrite and 3-way modes that write the changes into source code, on top of existing patch mode that creates a patch file.

    npx playwright test --update-snapshots=changed --update-source-method=3way
  • Option testConfig.webServer added a gracefulShutdown field for specifying a process kill signal other than the default SIGKILL.

  • Exposed testStep.attachments from the reporter API to allow retrieval of all attachments created by that step.

  • New option pathTemplate for toHaveScreenshot and toMatchAriaSnapshot assertions in the testConfig.expect configuration.

UI updates

  • Updated default HTML reporter to improve display of attachments.
  • New button in Codegen for picking elements to produce aria snapshots.
  • Additional details (such as keys pressed) are now displayed alongside action API calls in traces.
  • Display of canvas content in traces is error-prone. Display is now disabled by default, and can be enabled via the Display canvas content UI setting.
  • Call and Network panels now display additional time information.

Breaking

  • expect(locator).toBeEditable() and locator.isEditable() now throw if the target element is not , elements.

    await page.getByLabel('Upload directory').setInputFiles(path.join(__dirname, 'mydir'));
  • Multiple methods like locator.click() or locator.press() now support a ControlOrMeta modifier key. This key maps to Meta on macOS and maps to Control on Windows and Linux.

    // Press the common keyboard shortcut Control+S or Meta+S to trigger a "Save" operation.
    await page.keyboard.press('ControlOrMeta+S');
  • New property httpCredentials.send in apiRequest.newContext() that allows to either always send the Authorization header or only send it in response to 401 Unauthorized.

  • New option reason in apiRequestContext.dispose() that will be included in the error message of ongoing operations interrupted by the context disposal.

  • New option host in browserType.launchServer() allows to accept websocket connections on a specific address instead of unspecified 0.0.0.0.

  • Playwright now supports Chromium, Firefox and WebKit on Ubuntu 24.04.

  • v1.45 is the last release to receive WebKit update for macOS 12 Monterey. Please update macOS to keep using the latest WebKit.

Browser Versions

  • Chromium 127.0.6533.5
  • Mozilla Firefox 127.0
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 126
  • Microsoft Edge 126

Version 1.44

New APIs

Accessibility assertions

  • expect(locator).toHaveAccessibleName() checks if the element has the specified accessible name:

    const locator = page.getByRole('button');
    await expect(locator).toHaveAccessibleName('Submit');
  • expect(locator).toHaveAccessibleDescription() checks if the element has the specified accessible description:

    const locator = page.getByRole('button');
    await expect(locator).toHaveAccessibleDescription('Upload a photo');
  • expect(locator).toHaveRole() checks if the element has the specified ARIA role:

    const locator = page.getByTestId('save-button');
    await expect(locator).toHaveRole('button');

Locator handler

  • After executing the handler added with page.addLocatorHandler(), Playwright will now wait until the overlay that triggered the handler is not visible anymore. You can opt-out of this behavior with the new noWaitAfter option.
  • You can use new times option in page.addLocatorHandler() to specify maximum number of times the handler should be run.
  • The handler in page.addLocatorHandler() now accepts the locator as argument.
  • New page.removeLocatorHandler() method for removing previously added locator handlers.
const locator = page.getByText('This interstitial covers the button');
await page.addLocatorHandler(locator, async overlay => {
await overlay.locator('#close').click();
}, { times: 3, noWaitAfter: true });
// Run your tests that can be interrupted by the overlay.
// ...
await page.removeLocatorHandler(locator);

Miscellaneous options

  • multipart option in apiRequestContext.fetch() now accepts FormData and supports repeating fields with the same name.

    const formData = new FormData();
    formData.append('file', new File(['let x = 2024;'], 'f1.js', { type: 'text/javascript' }));
    formData.append('file', new File(['hello'], 'f2.txt', { type: 'text/plain' }));
    context.request.post('https://example.com/uploadFiles', {
    multipart: formData
    });
  • expect(callback).toPass({ intervals }) can now be configured by expect.toPass.intervals option globally in testConfig.expect or per project in testProject.expect.

  • expect(page).toHaveURL(url) now supports ignoreCase option.

  • testProject.ignoreSnapshots allows to configure per project whether to skip screenshot expectations.

Reporter API

  • New method suite.entries() returns child test suites and test cases in their declaration order. suite.type and testCase.type can be used to tell apart test cases and suites in the list.
  • Blob reporter now allows overriding report file path with a single option outputFile. The same option can also be specified as PLAYWRIGHT_BLOB_OUTPUT_FILE environment variable that might be more convenient on CI/CD.
  • JUnit reporter now supports includeProjectInTestName option.

Command line

  • --last-failed CLI option to for running only tests that failed in the previous run.

    First run all tests:

    $ npx playwright test

    Running 103 tests using 5 workers
    ...
    2 failed
    [chromium] › my-test.spec.ts:8:5 › two ─────────────────────────────────────────────────────────
    [chromium] › my-test.spec.ts:13:5 › three ──────────────────────────────────────────────────────
    101 passed (30.0s)

    Now fix the failing tests and run Playwright again with --last-failed option:

    $ npx playwright test --last-failed

    Running 2 tests using 2 workers
    2 passed (1.2s)

Browser Versions

  • Chromium 125.0.6422.14
  • Mozilla Firefox 125.0.1
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 124
  • Microsoft Edge 124

Version 1.43

New APIs

  • Method browserContext.clearCookies() now supports filters to remove only some cookies.

    // Clear all cookies.
    await context.clearCookies();
    // New: clear cookies with a particular name.
    await context.clearCookies({ name: 'session-id' });
    // New: clear cookies for a particular domain.
    await context.clearCookies({ domain: 'my-origin.com' });
  • New mode retain-on-first-failure for testOptions.trace. In this mode, trace is recorded for the first run of each test, but not for retires. When test run fails, the trace file is retained, otherwise it is removed.

    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    use: {
    trace: 'retain-on-first-failure',
    },
    });
  • New property testInfo.tags exposes test tags during test execution.

    test('example', async ({ page }) => {
    console.log(test.info().tags);
    });
  • New method locator.contentFrame() converts a Locator object to a FrameLocator. This can be useful when you have a Locator object obtained somewhere, and later on would like to interact with the content inside the frame.

    const locator = page.locator('iframe[name="embedded"]');
    // ...
    const frameLocator = locator.contentFrame();
    await frameLocator.getByRole('button').click();
  • New method frameLocator.owner() converts a FrameLocator object to a Locator. This can be useful when you have a FrameLocator object obtained somewhere, and later on would like to interact with the iframe element.

    const frameLocator = page.frameLocator('iframe[name="embedded"]');
    // ...
    const locator = frameLocator.owner();
    await expect(locator).toBeVisible();

UI Mode Updates

Playwright UI Mode

  • See tags in the test list.
  • Filter by tags by typing @fast or clicking on the tag itself.
  • New shortcuts:
    • "F5" to run tests.
    • "Shift F5" to stop running tests.
    • "Ctrl `" to toggle test output.

Browser Versions

  • Chromium 124.0.6367.8
  • Mozilla Firefox 124.0
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 123
  • Microsoft Edge 123

Version 1.42

New APIs

  • New method page.addLocatorHandler() registers a callback that will be invoked when specified element becomes visible and may block Playwright actions. The callback can get rid of the overlay. Here is an example that closes a cookie dialog when it appears:
// Setup the handler.
await page.addLocatorHandler(
page.getByRole('heading', { name: 'Hej! You are in control of your cookies.' }),
async () => {
await page.getByRole('button', { name: 'Accept all' }).click();
});
// Write the test as usual.
await page.goto('https://www.ikea.com/');
await page.getByRole('link', { name: 'Collection of blue and white' }).click();
await expect(page.getByRole('heading', { name: 'Light and easy' })).toBeVisible();
electronApp.on('console', async msg => {
const values = [];
for (const arg of msg.args())
values.push(await arg.jsonValue());
console.log(...values);
});
await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
  • New syntax for adding tags to the tests (@-tokens in the test title are still supported):
test('test customer login', {
tag: ['@fast', '@login'],
}, async ({ page }) => {
// ...
});

Use --grep command line option to run only tests with certain tags.

npx playwright test --grep @fast
  • --project command line flag now supports '*' wildcard:
npx playwright test --project='*mobile*'
test('test full report', {
annotation: [
{ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23180' },
{ type: 'docs', description: 'https://playwright.dev/docs/test-annotations#tag-tests' },
],
}, async ({ page }) => {
// ...
});

Announcements

  • ⚠️ Ubuntu 18 is not supported anymore.

Browser Versions

  • Chromium 123.0.6312.4
  • Mozilla Firefox 123.0
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 122
  • Microsoft Edge 123

Version 1.41

New APIs

Browser Versions

  • Chromium 121.0.6167.57
  • Mozilla Firefox 121.0
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 120
  • Microsoft Edge 120

Version 1.40

Test Generator Update

Playwright Test Generator

New tools to generate assertions:

Here is an example of a generated test with assertions:

import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.getByRole('link', { name: 'Get started' }).click();
await expect(page.getByLabel('Breadcrumbs').getByRole('list')).toContainText('Installation');
await expect(page.getByLabel('Search')).toBeVisible();
await page.getByLabel('Search').click();
await page.getByPlaceholder('Search docs').fill('locator');
await expect(page.getByPlaceholder('Search docs')).toHaveValue('locator');
});

New APIs

Other Changes

Browser Versions

  • Chromium 120.0.6099.28
  • Mozilla Firefox 119.0
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 119
  • Microsoft Edge 119

Version 1.39

Add custom matchers to your expect

You can extend Playwright assertions by providing custom matchers. These matchers will be available on the expect object.

test.spec.ts
import { expect as baseExpect } from '@playwright/test';
export const expect = baseExpect.extend({
async toHaveAmount(locator: Locator, expected: number, options?: { timeout?: number }) {
// ... see documentation for how to write matchers.
},
});

test('pass', async ({ page }) => {
await expect(page.getByTestId('cart')).toHaveAmount(5);
});

See the documentation for a full example.

Merge test fixtures

You can now merge test fixtures from multiple files or modules:

fixtures.ts
import { mergeTests } from '@playwright/test';
import { test as dbTest } from 'database-test-utils';
import { test as a11yTest } from 'a11y-test-utils';

export const test = mergeTests(dbTest, a11yTest);
test.spec.ts
import { test } from './fixtures';

test('passes', async ({ database, page, a11y }) => {
// use database and a11y fixtures.
});

Merge custom expect matchers

You can now merge custom expect matchers from multiple files or modules:

fixtures.ts
import { mergeTests, mergeExpects } from '@playwright/test';
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';

export const test = mergeTests(dbTest, a11yTest);
export const expect = mergeExpects(dbExpect, a11yExpect);
test.spec.ts
import { test, expect } from './fixtures';

test('passes', async ({ page, database }) => {
await expect(database).toHaveDatabaseUser('admin');
await expect(page).toPassA11yAudit();
});

Hide implementation details: box test steps

You can mark a test.step() as "boxed" so that errors inside it point to the step call site.

async function login(page) {
await test.step('login', async () => {
// ...
}, { box: true }); // Note the "box" option here.
}
Error: Timed out 5000ms waiting for expect(locator).toBeVisible()
... error details omitted ...

14 | await page.goto('https://github.com/login');
> 15 | await login(page);
| ^
16 | });

See test.step() documentation for a full example.

New APIs

Browser Versions

  • Chromium 119.0.6045.9
  • Mozilla Firefox 118.0.1
  • WebKit 17.4

This version was also tested against the following stable channels:

  • Google Chrome 118
  • Microsoft Edge 118

Version 1.38

UI Mode Updates

Playwright UI Mode

  1. Zoom into time range.
  2. Network panel redesign.

New APIs

Deprecations

Breaking Changes: Playwright no longer downloads browsers automatically

Note: If you are using @playwright/test package, this change does not affect you.

Playwright recommends to use @playwright/test package and download browsers via npx playwright install command. If you are following this recommendation, nothing has changed for you.

However, up to v1.38, installing the playwright package instead of @playwright/test did automatically download browsers. This is no longer the case, and we recommend to explicitly download browsers via npx playwright install command.

v1.37 and earlier

playwright package was downloading browsers during npm install, while @playwright/test was not.

v1.38 and later

playwright and @playwright/test packages do not download browsers during npm install.

Recommended migration

Run npx playwright install to download browsers after npm install. For example, in your CI configuration:

- run: npm ci
- run: npx playwright install --with-deps

Alternative migration option - not recommended

Add @playwright/browser-chromium, @playwright/browser-firefox and @playwright/browser-webkit as a dependency. These packages download respective browsers during npm install. Make sure you keep the version of all playwright packages in sync:

// package.json
{
"devDependencies": {
"playwright": "1.38.0",
"@playwright/browser-chromium": "1.38.0",
"@playwright/browser-firefox": "1.38.0",
"@playwright/browser-webkit": "1.38.0"
}
}

Browser Versions

  • Chromium 117.0.5938.62
  • Mozilla Firefox 117.0
  • WebKit 17.0

This version was also tested against the following stable channels:

  • Google Chrome 116
  • Microsoft Edge 116

Version 1.37

New npx playwright merge-reports tool

If you run tests on multiple shards, you can now merge all reports in a single HTML report (or any other report) using the new merge-reports CLI tool.

Using merge-reports tool requires the following steps:

  1. Adding a new "blob" reporter to the config when running on CI:

    playwright.config.ts
    export default defineConfig({
    testDir: './tests',
    reporter: process.env.CI ? 'blob' : 'html',
    });

    The "blob" reporter will produce ".zip" files that contain all the information about the test run.

  2. Copying all "blob" reports in a single shared location and running npx playwright merge-reports:

npx playwright merge-reports --reporter html ./all-blob-reports

Read more in our documentation.

📚 Debian 12 Bookworm Support

Playwright now supports Debian 12 Bookworm on both x86_64 and arm64 for Chromium, Firefox and WebKit. Let us know if you encounter any issues!

Linux support looks like this:

Ubuntu 20.04Ubuntu 22.04Debian 11Debian 12
Chromium
WebKit
Firefox

UI Mode Updates

  • UI Mode now respects project dependencies. You can control which dependencies to respect by checking/unchecking them in a projects list.
  • Console logs from the test are now displayed in the Console tab.

Browser Versions

  • Chromium 116.0.5845.82
  • Mozilla Firefox 115.0
  • WebKit 17.0

This version was also tested against the following stable channels:

  • Google Chrome 115
  • Microsoft Edge 115

Version 1.36

🏝️ Summer maintenance release.

Browser Versions

  • Chromium 115.0.5790.75
  • Mozilla Firefox 115.0
  • WebKit 17.0

This version was also tested against the following stable channels:

  • Google Chrome 114
  • Microsoft Edge 114

Version 1.35

Highlights

  • UI mode is now available in VSCode Playwright extension via a new "Show trace viewer" button:

    Playwright UI Mode

  • UI mode and trace viewer mark network requests handled with page.route() and browserContext.route() handlers, as well as those issued via the API testing:

    Trace Viewer

  • New option maskColor for methods page.screenshot(), locator.screenshot(), expect(page).toHaveScreenshot() and expect(locator).toHaveScreenshot() to change default masking color:

    await page.goto('https://playwright.dev');
    await expect(page).toHaveScreenshot({
    mask: [page.locator('img')],
    maskColor: '#00FF00', // green
    });
  • New uninstall CLI command to uninstall browser binaries:

    $ npx playwright uninstall # remove browsers installed by this installation
    $ npx playwright uninstall --all # remove all ever-install Playwright browsers
  • Both UI mode and trace viewer now could be opened in a browser tab:

    $ npx playwright test --ui-port 0 # open UI mode in a tab on a random port
    $ npx playwright show-trace --port 0 # open trace viewer in tab on a random port

⚠️ Breaking changes

  • playwright-core binary got renamed from playwright to playwright-core. So if you use playwright-core CLI, make sure to update the name:

    $ npx playwright-core install # the new way to install browsers when using playwright-core

    This change does not affect @playwright/test and playwright package users.

Browser Versions

  • Chromium 115.0.5790.13
  • Mozilla Firefox 113.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 114
  • Microsoft Edge 114

Version 1.34

Highlights

  • UI Mode now shows steps, fixtures and attachments: UI Mode attachments

  • New property testProject.teardown to specify a project that needs to run after this and all dependent projects have finished. Teardown is useful to cleanup any resources acquired by this project.

    A common pattern would be a setup dependency with a corresponding teardown:

    playwright.config.ts
    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    projects: [
    {
    name: 'setup',
    testMatch: /global.setup\.ts/,
    teardown: 'teardown',
    },
    {
    name: 'teardown',
    testMatch: /global.teardown\.ts/,
    },
    {
    name: 'chromium',
    use: devices['Desktop Chrome'],
    dependencies: ['setup'],
    },
    {
    name: 'firefox',
    use: devices['Desktop Firefox'],
    dependencies: ['setup'],
    },
    {
    name: 'webkit',
    use: devices['Desktop Safari'],
    dependencies: ['setup'],
    },
    ],
    });
  • New method expect.configure to create pre-configured expect instance with its own defaults such as timeout and soft.

    const slowExpect = expect.configure({ timeout: 10000 });
    await slowExpect(locator).toHaveText('Submit');

    // Always do soft assertions.
    const softExpect = expect.configure({ soft: true });
  • New options stderr and stdout in testConfig.webServer to configure output handling:

    playwright.config.ts
    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    // Run your local dev server before starting the tests
    webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3000',
    reuseExistingServer: !process.env.CI,
    stdout: 'pipe',
    stderr: 'pipe',
    },
    });
  • New locator.and() to create a locator that matches both locators.

    const button = page.getByRole('button').and(page.getByTitle('Subscribe'));
  • New events browserContext.on('console') and browserContext.on('dialog') to subscribe to any dialogs and console messages from any page from the given browser context. Use the new methods consoleMessage.page() and dialog.page() to pin-point event source.

⚠️ Breaking changes

  • npx playwright test no longer works if you install both playwright and @playwright/test. There's no need to install both, since you can always import browser automation APIs from @playwright/test directly:

    automation.ts
    import { chromium, firefox, webkit } from '@playwright/test';
    /* ... */
  • Node.js 14 is no longer supported since it reached its end-of-life on April 30, 2023.

Browser Versions

  • Chromium 114.0.5735.26
  • Mozilla Firefox 113.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 113
  • Microsoft Edge 113

Version 1.33

Locators Update

  • Use locator.or() to create a locator that matches either of the two locators. Consider a scenario where you'd like to click on a "New email" button, but sometimes a security settings dialog shows up instead. In this case, you can wait for either a "New email" button, or a dialog and act accordingly:

    const newEmail = page.getByRole('button', { name: 'New email' });
    const dialog = page.getByText('Confirm security settings');
    await expect(newEmail.or(dialog)).toBeVisible();
    if (await dialog.isVisible())
    await page.getByRole('button', { name: 'Dismiss' }).click();
    await newEmail.click();
  • Use new options hasNot and hasNotText in locator.filter() to find elements that do not match certain conditions.

    const rowLocator = page.locator('tr');
    await rowLocator
    .filter({ hasNotText: 'text in column 1' })
    .filter({ hasNot: page.getByRole('button', { name: 'column 2 button' }) })
    .screenshot();
  • Use new web-first assertion expect(locator).toBeAttached() to ensure that the element is present in the page's DOM. Do not confuse with the expect(locator).toBeVisible() that ensures that element is both attached & visible.

New APIs

⚠️ Breaking change

  • The mcr.microsoft.com/playwright:v1.33.0 now serves a Playwright image based on Ubuntu Jammy. To use the focal-based image, please use mcr.microsoft.com/playwright:v1.33.0-focal instead.

Browser Versions

  • Chromium 113.0.5672.53
  • Mozilla Firefox 112.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 112
  • Microsoft Edge 112

Version 1.32

Introducing UI Mode (preview)

New UI Mode lets you explore, run and debug tests. Comes with a built-in watch mode.

Playwright UI Mode

Engage with a new flag --ui:

npx playwright test --ui

New APIs

⚠️ Breaking change in component tests

Note: component tests only, does not affect end-to-end tests.

  • @playwright/experimental-ct-react now supports React 18 only.
  • If you're running component tests with React 16 or 17, please replace @playwright/experimental-ct-react with @playwright/experimental-ct-react17.

Browser Versions

  • Chromium 112.0.5615.29
  • Mozilla Firefox 111.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 111
  • Microsoft Edge 111

Version 1.31

New APIs

  • New property testProject.dependencies to configure dependencies between projects.

    Using dependencies allows global setup to produce traces and other artifacts, see the setup steps in the test report and more.

    playwright.config.ts
    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    projects: [
    {
    name: 'setup',
    testMatch: /global.setup\.ts/,
    },
    {
    name: 'chromium',
    use: devices['Desktop Chrome'],
    dependencies: ['setup'],
    },
    {
    name: 'firefox',
    use: devices['Desktop Firefox'],
    dependencies: ['setup'],
    },
    {
    name: 'webkit',
    use: devices['Desktop Safari'],
    dependencies: ['setup'],
    },
    ],
    });
  • New assertion expect(locator).toBeInViewport() ensures that locator points to an element that intersects viewport, according to the intersection observer API.

    const button = page.getByRole('button');

    // Make sure at least some part of element intersects viewport.
    await expect(button).toBeInViewport();

    // Make sure element is fully outside of viewport.
    await expect(button).not.toBeInViewport();

    // Make sure that at least half of the element intersects viewport.
    await expect(button).toBeInViewport({ ratio: 0.5 });

Miscellaneous

  • DOM snapshots in trace viewer can be now opened in a separate window.
  • New method defineConfig to be used in playwright.config.
  • New option maxRedirects for method route.fetch().
  • Playwright now supports Debian 11 arm64.
  • Official docker images now include Node 18 instead of Node 16.

⚠️ Breaking change in component tests

Note: component tests only, does not affect end-to-end tests.

playwright-ct.config configuration file for component testing now requires calling defineConfig.

// Before

import { type PlaywrightTestConfig, devices } from '@playwright/experimental-ct-react';
const config: PlaywrightTestConfig = {
// ... config goes here ...
};
export default config;

Replace config variable definition with defineConfig call:

// After

import { defineConfig, devices } from '@playwright/experimental-ct-react';
export default defineConfig({
// ... config goes here ...
});

Browser Versions

  • Chromium 111.0.5563.19
  • Mozilla Firefox 109.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 110
  • Microsoft Edge 110

Version 1.30

Browser Versions

  • Chromium 110.0.5481.38
  • Mozilla Firefox 108.0.2
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 109
  • Microsoft Edge 109

Version 1.29

New APIs

  • New method route.fetch() and new option json for route.fulfill():

    await page.route('**/api/settings', async route => {
    // Fetch original settings.
    const response = await route.fetch();

    // Force settings theme to a predefined value.
    const json = await response.json();
    json.theme = 'Solorized';

    // Fulfill with modified data.
    await route.fulfill({ json });
    });
  • New method locator.all() to iterate over all matching elements:

    // Check all checkboxes!
    const checkboxes = page.getByRole('checkbox');
    for (const checkbox of await checkboxes.all())
    await checkbox.check();
  • locator.selectOption() matches now by value or label:

    <select multiple>
    <option value="red">Redoption>
    <option value="green">Greenoption>
    <option value="blue">Blueoption>
    select>
    await element.selectOption('Red');
  • Retry blocks of code until all assertions pass:

    await expect(async () => {
    const response = await page.request.get('https://api.example.com');
    await expect(response).toBeOK();
    }).toPass();

    Read more in our documentation.

  • Automatically capture full page screenshot on test failure:

    playwright.config.ts
    import { defineConfig } from '@playwright/test';
    export default defineConfig({
    use: {
    screenshot: {
    mode: 'only-on-failure',
    fullPage: true,
    }
    }
    });

Miscellaneous

Browser Versions

  • Chromium 109.0.5414.46
  • Mozilla Firefox 107.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 108
  • Microsoft Edge 108

Version 1.28

Playwright Tools

  • Record at Cursor in VSCode. You can run the test, position the cursor at the end of the test and continue generating the test.

New VSCode Extension

  • Live Locators in VSCode. You can hover and edit locators in VSCode to get them highlighted in the opened browser.
  • Live Locators in CodeGen. Generate a locator for any element on the page using "Explore" tool.

Locator Explorer

  • Codegen and Trace Viewer Dark Theme. Automatically picked up from operating system settings.

Dark Theme

Test Runner

New APIs

Browser Versions

  • Chromium 108.0.5359.29
  • Mozilla Firefox 106.0
  • WebKit 16.4

This version was also tested against the following stable channels:

  • Google Chrome 107
  • Microsoft Edge 107

Version 1.27

Locators

With these new APIs writing locators is a joy:

await page.getByLabel('User Name').fill('John');

await page.getByLabel('Password').fill('secret-password');

await page.getByRole('button', { name: 'Sign in' }).click();

await expect(page.getByText('Welcome, John!')).toBeVisible();

All the same methods are also available on Locator, FrameLocator and Frame classes.

Other highlights

  • workers option in the playwright.config.ts now accepts a percentage string to use some of the available CPUs. You can also pass it in the command line:

    npx playwright test --workers=20%
  • New options host and port for the html reporter.

    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    reporter: [['html', { host: 'localhost', port: '9223' }]],
    });
  • New field FullConfig.configFile is available to test reporters, specifying the path to the config file if any.

  • As announced in v1.25, Ubuntu 18 will not be supported as of Dec 2022. In addition to that, there will be no WebKit updates on Ubuntu 18 starting from the next Playwright release.

Behavior Changes

  • expect(locator).toHaveAttribute() with an empty value does not match missing attribute anymore. For example, the following snippet will succeed when button does not have a disabled attribute.

    await expect(page.getByRole('button')).toHaveAttribute('disabled', '');
  • Command line options --grep and --grep-invert previously incorrectly ignored grep and grepInvert options specified in the config. Now all of them are applied together.

Browser Versions

  • Chromium 107.0.5304.18
  • Mozilla Firefox 105.0.1
  • WebKit 16.0

This version was also tested against the following stable channels:

  • Google Chrome 106
  • Microsoft Edge 106

Version 1.26

Assertions

Other highlights

  • New option maxRedirects for apiRequestContext.get() and others to limit redirect count.
  • New command-line flag --pass-with-no-tests that allows the test suite to pass when no files are found.
  • New command-line flag --ignore-snapshots to skip snapshot expectations, such as expect(value).toMatchSnapshot() and expect(page).toHaveScreenshot().

Behavior Change

A bunch of Playwright APIs already support the waitUntil: 'domcontentloaded' option. For example:

await page.goto('https://playwright.dev', {
waitUntil: 'domcontentloaded',
});

Prior to 1.26, this would wait for all iframes to fire the DOMContentLoaded event.

To align with web specification, the 'domcontentloaded' value only waits for the target frame to fire the 'DOMContentLoaded' event. Use waitUntil: 'load' to wait for all iframes.

Browser Versions

  • Chromium 106.0.5249.30
  • Mozilla Firefox 104.0
  • WebKit 16.0

This version was also tested against the following stable channels:

  • Google Chrome 105
  • Microsoft Edge 105

Version 1.25

VSCode Extension

  • Watch your tests running live & keep devtools open.
  • Pick selector.
  • Record new test from current page state.

vscode extension screenshot

Test Runner

  • test.step() now returns the value of the step function:

    test('should work', async ({ page }) => {
    const pageTitle = await test.step('get title', async () => {
    await page.goto('https://playwright.dev');
    return await page.title();
    });
    console.log(pageTitle);
    });
  • Added test.describe.fixme().

  • New 'interrupted' test status.

  • Enable tracing via CLI flag: npx playwright test --trace=on.

Announcements

  • 🎁 We now ship Ubuntu 22.04 Jammy Jellyfish docker image: mcr.microsoft.com/playwright:v1.34.0-jammy.
  • 🪦 This is the last release with macOS 10.15 support (deprecated as of 1.21).
  • 🪦 This is the last release with Node.js 12 support, we recommend upgrading to Node.js LTS (16).
  • ⚠️ Ubuntu 18 is now deprecated and will not be supported as of Dec 2022.

Browser Versions

  • Chromium 105.0.5195.19
  • Mozilla Firefox 103.0
  • WebKit 16.0

This version was also tested against the following stable channels:

  • Google Chrome 104
  • Microsoft Edge 104

Version 1.24

🌍 Multiple Web Servers in playwright.config.ts

Launch multiple web servers, databases, or other processes by passing an array of configurations:

playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: [
{
command: 'npm run start',
url: 'http://127.0.0.1:3000',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
},
{
command: 'npm run backend',
url: 'http://127.0.0.1:3333',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
}
],
use: {
baseURL: 'http://localhost:3000/',
},
});

🐂 Debian 11 Bullseye Support

Playwright now supports Debian 11 Bullseye on x86_64 for Chromium, Firefox and WebKit. Let us know if you encounter any issues!

Linux support looks like this:

| | Ubuntu 20.04 | Ubuntu 22.04 | Debian 11 | :--- | :---: | :---: | :---: | :---: | | Chromium | ✅ | ✅ | ✅ | | WebKit | ✅ | ✅ | ✅ | | Firefox | ✅ | ✅ | ✅ |

🕵️ Anonymous Describe

It is now possible to call test.describe() to create suites without a title. This is useful for giving a group of tests a common option with test.use().

test.describe(() => {
test.use({ colorScheme: 'dark' });

test('one', async ({ page }) => {
// ...
});

test('two', async ({ page }) => {
// ...
});
});

🧩 Component Tests Update

Playwright 1.24 Component Tests introduce beforeMount and afterMount hooks. Use these to configure your app for tests.

For example, this could be used to setup App router in Vue.js:

src/component.spec.ts
import { test } from '@playwright/experimental-ct-vue';
import { Component } from './mycomponent';

test('should work', async ({ mount }) => {
const component = await mount(Component, {
hooksConfig: {
/* anything to configure your app */
}
});
});
playwright/index.ts
import { router } from '../router';
import { beforeMount } from '@playwright/experimental-ct-vue/hooks';

beforeMount(async ({ app, hooksConfig }) => {
app.use(router);
});

A similar configuration in Next.js would look like this:

src/component.spec.jsx
import { test } from '@playwright/experimental-ct-react';
import { Component } from './mycomponent';

test('should work', async ({ mount }) => {
const component = await mount(<Component></Component>, {
// Pass mock value from test into `beforeMount`.
hooksConfig: {
router: {
query: { page: 1, per_page: 10 },
asPath: '/posts'
}
}
});
});
playwright/index.js
import router from 'next/router';
import { beforeMount } from '@playwright/experimental-ct-react/hooks';

beforeMount(async ({ hooksConfig }) => {
// Before mount, redefine useRouter to return mock value from test.
router.useRouter = () => hooksConfig.router;
});

Version 1.23

Network Replay

Now you can record network traffic into a HAR file and re-use this traffic in your tests.

To record network into HAR file:

npx playwright open --save-har=github.har.zip https://github.com/microsoft

Alternatively, you can record HAR programmatically:

const context = await browser.newContext({
recordHar: { path: 'github.har.zip' }
});
// ... do stuff ...
await context.close();

Use the new methods page.routeFromHAR() or browserContext.routeFromHAR() to serve matching responses from the HAR file:

await context.routeFromHAR('github.har.zip');

Read more in our documentation.

Advanced Routing

You can now use route.fallback() to defer routing to other handlers.

Consider the following example:

// Remove a header from all requests.
test.beforeEach(async ({ page }) => {
await page.route('**/*', async route => {
const headers = await route.request().allHeaders();
delete headers['if-none-match'];
await route.fallback({ headers });
});
});

test('should work', async ({ page }) => {
await page.route('**/*', async route => {
if (route.request().resourceType() === 'image')
await route.abort();
else
await route.fallback();
});
});

Note that the new methods page.routeFromHAR() and browserContext.routeFromHAR() also participate in routing and could be deferred to.

Web-First Assertions Update

  • New method expect(locator).toHaveValues() that asserts all selected values of