Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://github.com/microsoft/playwright/issues/30300 - [REGRESSION]: UI mode restarts if keep storage state https://github.com/microsoft/playwright/issues/30339 - [REGRESSION]: Brand new install of playwright, unable to run chromium with show browser using vscode
This version was also tested against the following stable channels:
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();
@fast
or clicking on the tag itself.This version was also tested against the following stable channels:
https://github.com/microsoft/playwright/issues/29732 - [Regression]: HEAD requests to webServer.url since v1.42.0 https://github.com/microsoft/playwright/issues/29746 - [Regression]: Playwright CT CLI scripts fail due to broken initializePlugin import https://github.com/microsoft/playwright/issues/29739 - [Bug]: Component tests fails when imported a module with a dot in a name https://github.com/microsoft/playwright/issues/29731 - [Regression]: 1.42.0 breaks some import statements https://github.com/microsoft/playwright/issues/29760 - [Bug]: Possible regression with chained locators in v1.42
This version was also tested against the following stable channels:
Test tags
New tag 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
Annotating skipped tests
New annotation syntax for test annotations allows annotating the tests that do not run.
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 }) => {
// ...
});
page.addLocatorHandler()
[!WARNING] This feature is experimental, we are actively looking for the feedback based on your scenarios.
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();
Project wildcard filter Playwright command line flag now supports '*' wildcard when filtering by project.
npx playwright test --project='*mobile*'
Other APIs
expect(callback).toPass({ timeout })
The timeout can now be configured by expect.toPass.timeout
option globally or in project config
electronApplication.on('console') electronApplication.on('console') event is emitted when Electron main process calls console API methods.
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' }));
page.pdf() accepts two new options tagged
and outline
.
Mixing the test instances in the same suite is no longer supported. Allowing it was an oversight as it makes reasoning about the semantics unnecessarily hard.
const test = baseTest.extend({ item: async ({}, use) => {} });
baseTest.describe('Admin user', () => {
test('1', async ({ page, item }) => {});
test('2', async ({ page, item }) => {});
});
This version was also tested against the following stable channels:
https://github.com/microsoft/playwright/issues/29123 - [REGRESSION] route.continue: Protocol error (Fetch.continueRequest): Invalid InterceptionId.
This version was also tested against the following stable channels:
https://github.com/microsoft/playwright/issues/29067 - [REGRESSION] Codegen/Recorder: not all clicks are being actioned nor recorded https://github.com/microsoft/playwright/issues/29028 - [REGRESSION] React component tests throw type error when passing null/undefined to component https://github.com/microsoft/playwright/issues/29027 - [REGRESSION] React component tests not passing Date prop values https://github.com/microsoft/playwright/issues/29023 - [REGRESSION] React component tests not rendering children prop https://github.com/microsoft/playwright/issues/29019 - [REGRESSION] trace.playwright.dev does not currently support the loading from URL
This version was also tested against the following stable channels:
style
in page.screenshot([options]) and locator.screenshot([options]) to add custom CSS to the page before taking a screenshot.stylePath
for methods expect(page).toHaveScreenshot(name[, options]) and expect(locator).toHaveScreenshot(name[, options]) to apply a custom stylesheet while making the screenshot.fileName
option for Blob reporter, to specify the name of the report to be created.This version was also tested against the following stable channels:
https://github.com/microsoft/playwright/issues/28319 - [REGRESSION]: Version 1.40.0 Produces corrupted traces https://github.com/microsoft/playwright/issues/28371 - [BUG] The color of the 'ok' text did not change to green in the vs code test results section https://github.com/microsoft/playwright/issues/28321 - [BUG] Ambiguous test outcome and status for serial mode https://github.com/microsoft/playwright/issues/28362 - [BUG] Merging blobs ends up in Error: Cannot create a string longer than 0x1fffffe8 characters https://github.com/microsoft/playwright/pull/28239 - fix: collect all errors in removeFolders
This version was also tested against the following stable channels:
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');
});
reason
in page.close(), browserContext.close() and browser.close(). Close reason is reported for all operations interrupted by the closure.firefoxUserPrefs
in browserType.launchPersistentContext(userDataDir).This version was also tested against the following stable channels:
You can extend Playwright assertions by providing custom matchers. These matchers will be available on the expect object.
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.
You can now merge test fixtures from multiple files or modules:
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);
import { test } from './fixtures';
test('passes', async ({ database, page, a11y }) => {
// use database and a11y fixtures.
});
You can now merge custom expect matchers from multiple files or modules:
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);
import { test, expect } from './fixtures';
test('passes', async ({ page, database }) => {
await expect(database).toHaveDatabaseUser('admin');
await expect(page).toPassA11yAudit();
});
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.
This version was also tested against the following stable channels: