Written by Antonello Zanini✏️
Playwright is a browser automation framework available in multiple programming languages. In the fast-paced world of web development, Playwright has become one of the leading technologies for writing end-to-end tests for modern web applications, thanks to its rich and intuitive API.
Join us in this adoption guide and get ready to learn everything you need to know about Playwright and why to use it in your browser automation projects!
Introduction to Playwright
Playwright is a cross-browser, cross-language, cross-platform browser automation framework developed by Microsoft. Originally created to meet the needs of end-to-end testing, it can cover many other user cases as well. It provides an intuitive, easy-to-learn, unified API for interacting with all modern rendering engines, including Chromium, WebKit, and Firefox.
Playwright works on Windows, Linux, and macOS; locally or on CI; on desktop or emulated mobile browsers; and in headless or headed mode. The framework supports several platforms and programming languages, such as JavaScript and TypeScript, Java, Python, and .NET.
Let’s now take a step back and review Playwright’s history before seeing what it offers, its main use cases, and how to get started with it.
History of Playwright
Playwright was introduced by Microsoft in January 2020. The development team included engineers who had previously worked on Google's Puppeteer project, the most popular JavaScript-based automated testing framework at the time.
The team's experience with that technology helped them build a more flexible and modern framework that could overcome Puppeteer's well-known limitations and shortcomings. For example, they immediately recognized the need for a tool that could support multiple browsers and not only Chromium-based browsers.
On 6 May 2020, the first stable version of Playwright was released. This included full support for Chromium, Firefox, and WebKit, establishing Playwright as a comprehensive cross-browser testing tool.
The Playwright Node.js test runner was released later as part of an effort to provide a more complete solution for running browser-based tests. Its development was driven by the need for a tool that could fully leverage the Playwright API and make end-to-end testing more robust and straightforward.
Since its initial release, Playwright has rapidly evolved. The team has worked hard to to make the framework more robust and extensive by keep adding new features. These include improved selectors, auto-wait mechanisms, network interception, device emulation, and integrations with popular CI/CD systems and testing frameworks.
With over 62k stars on GitHub and more than 5 million weekly downloads on npm, Playwright is now a leading browser automation technology. Its community boasts thousands of active users, with extensive documentation, tutorials, and community-driven content contributing to its widespread adoption.
Further reading:
- Using Puppeteer for automated UI testing
- Headless browser testing guide
- Developing an effective CI/CD pipeline for frontend apps
How Playwright works: Playwright library vs. Playwright Test
To better understand how Playwright works, we need to dig into its two main components:
- The Playwright library — The core component that provides the API for interacting with browsers. It supports the Chromium, Firefox, and WebKit browser engines, making it possible to interact with multiple browsers from a single script. Features offered by these APIs include browser context management, page navigation, DOM element selectors, user action simulation, and more
- Playwright Test — A test runner built specifically to work with the Playwright Library. It offers a complete environment for writing, organizing, and running automated tests. Features offered by this component include BDD test definition, assertions, parallel execution, result report generation, extended configuration, and more
In other words, the Playwright library exposes the low-level API for interacting with browsers. Meanwhile, Playwright Test brings the framework and tools needed to efficiently manage and execute tests built using that API. Together, they form a powerful toolkit that enables developers to create robust and reliable web automation scripts and tests.
Further reading:
Use cases for Playwright
Playwright’s use cases depend on whether we’re referring to the Playwright library or Playwright Test.
These are some of the most common use cases for the Playwright library:
- Web scraping — Scripts that can extract data from web pages by automating browser interactions and navigating through pages
- Browser automation bot development — Bots that automate repetitive tasks in the browser by simulating the behavior of a human user
These are some of the main use cases of Playwright Test:
- End-to-end testing — Simulate a specific user flow in a site or web application from start to finish to ensure that all components work together as intended on different browsers
- Component testing — Isolate individual components of a web application to test their functionality in different scenarios. As of this writing, this is still experimental in Plawyright
- API testing — Verify that the REST APIs exposed by a backend application produce the desired results by calling them directly or triggering them by automating user interaction with a frontend application in the browser
- Visual regression testing — Testing a web application to ensure that new code changes do not negatively affect layouts or user interface
Playwright as a whole covers all the use cases presented above and many more.
Further reading:
- The best Node.js web scrapers for your use case
- Node.js web scraping tutorial
- Getting started with Playwright component testing
- Using Playwright for end-to-end testing
Setting up a Playwright project
Playwright requires different setups depending on which of its two components you need to use. Since the framework is popular primarily for its testing capabilities, let's look at how to create a Playwright testing project in TypeScript using Node.js.
First, make sure you have Node.js installed on your machine. Then, run the command below in the project folder to start the Playwright setup wizard:
npm init playwright@latest
During the process, you will have to choose:
- Programming language to write your tests with (TypeScript or JavaScript)
- Name of the folder containing the test scripts
- Whether to add a GitHub Actions workflow to easily run tests on CI
- Whether to install Playwright browsers
After answering these questions, the installation tool will start downloading, installing, and configuring the required dependencies. At the end of this process, your project folder will contain a Playwright test suite.
The configured test folder will contain an example.spec.ts
test file you can run with this command:
npx playwright test
The result will be the following HTML report: Awesome, you just set up a Playwright testing project!
Anatomy of a Playwright script
Browser automation and test scripts follow two different structures in Playwright. We’ll go over how they work in the Playwright library and with Playwright Test.
Playwright library scripts
A Playwright Library browser automation script generally performs the three steps below:
- Launch a chosen browser directly
- Visit a web page and perform some operations on it
- Close the browser and release its resources
For example, this is what a simple web scraping Playwright script looks like:
const { chromium } = require("playwright");
(async () => {
// launch a new browser instance
const browser = await chromium.launch();
// create a new browser context
const context = await browser.newContext();
// create a new page in the browser context
const page = await context.newPage();
// locate the h1 element on the page
const firstH1 = await page.locator('h1');
// extract the text in the h1 element
const h1Text = await firstH1.textContent();
// print the scraped data in the console
console.log(h1Text);
// release the browser resources
await context.close();
await browser.close();
})();
Behind the scenes, Playwright instructs Chromium to visit the specified page, search for the <h1>
element, retrieve the text inside it, print it in the console, and close the browser.
Playwright Test scripts
In Playwright, a test is a sequence of commands enclosed in a test()
block. These commands are the building blocks of the test logic and are usually methods on the page
object provided by Playwright. Then, at the end of the test block, there is an except()
assertion method to verify that a specific condition is true.
Playwright tests have a BDD syntax and follow the AAA pattern:
- Arrange — Prepare the test environment, such as setting up a database with some specific data
- Act — Perform actions on the page, such as filling out forms or clicking buttons
- Assert — Check the state of the page against expectations
This is true for both unit and end-to-end tests.
In simple terms, a Playwright test performs actions on the application and verifies that it’s behaving as expected. Here is an example of a test:
import { test, expect } from "@playwright/test";
test("has title", async ({ page }) => {
await page.goto("https://playwright.dev/");
// expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});
test("get started link", async ({ page }) => {
await page.goto("https://playwright.dev/");
// click the get started link.
await page.getByRole("link", { name: "Get started" }).click();
// expects page to have a heading with the name of Installation.
await expect(page.getByRole("heading", { name: "Installation" })).toBeVisible();
});
Here, the test file contains two tests. The first test wraps the following two commands:
- Visit the URL
"https://playwright.dev/"
- Verify that the title contains the substring "Playwright"
The second test includes commands to:
- Visit the URL
"https://playwright.dev/"
- Click the link with the name "Get started"
- Verify that a heading with the name “Installation” is visible on the page
As you can notice, the commands are close to plain English and can be chained quite intuitively. This is what makes Playwright so popular — it ensures that tests are easy to write, read, and debug.
In Playwright, related tests can also be grouped together in a describe()
block, like this:
import { describe, test, expect } from "@playwright/test";
describe("User Authentication Tests", () => {
test("should let a user log in", async ({ page }) => {
// test logic for user login...
});
test("should let new users sign up", async ({ page }) => {
// test logic for new signups...
});
test("should let users reset their passwords", async ({ page }) => {
// test logic for password reset functionality...
});
});
describe()
blocks are called test groups and live inside a spec
file. All test groups in a spec
file are called a test suite.
The devices and browsers to execute these tests on, as well as many other options, can be configured locally or globally in configuration files. In a TypeScript testing project, the global configuration file is playwright.config.ts
.
Why choose Playwright?
Here are the main reasons why Playwright is such a popular option for browser automation, from its great ease of use to its extensive documentation and plethora of integrations:
- Cross-browser support — Playwright can run on Chrome, Firefox, Edge, Safari, and many other browsers. The same automated test or script can be run on different browsers without having to make code changes. This ensures that tested web applications run consistently across all major browsers, which is critical to reaching a wider audience and maintaining a high-quality user experience
- Multiple programming languages — The same Playwright API that thousands of developers love and are familiar with is available in JavaScript, TypeScript, Python, and .NET with some minor modifications to adapt the method names to the best naming practices of the different programming languages. There are also many other unofficial ports, such as Playwright Ruby or Playwright Go
- Many integrations — Playwright is compatible with all major CI/CD systems, including GitHub Actions, Docker, Azure Pipelines, CircleCI, Jenkins, Bitbucket Pipelines, GitLab CI, and Google Cloud Build. It also supports Visual Studio Code via a dedicated extension
- Easy setup and configuration — Playwright comes with an installation tool that simplifies project setup. The framework also features an integrated configurable test runner that supports parallel execution, custom reporting, CLI options, and more. This test runner simplifies the creation, configuration, and management of end-to-end testing
- Supported frameworks — Playwright's API can interact with any application running in a browser, regardless of the framework it was built in. That includes static sites, dynamic web pages, SPAs, and more. When it comes to component testing, it supports React, Vue, Svelte, and Solid
- Extensive community and support — Playwright has been on the crest of a wave for years now. The community is huge and there is a lot of information available on various sites and channels, including Discord, StackOverflow, YouTube, GitHub, and others
- Top-notch documentation — Playwright's official documentation is detailed, always up-to-date, covers all supported programming languages, and includes best practices and hundreds of examples. It is hard to ask for more from the documentation of a framework
Further reading:
Main limitations of Playwright
Playwright is an excellent tool with many features supporting several use cases, but it also has some limitations. The most critical ones are:
- Steep learning curve — Playwright's extensive feature set can be overwhelming for beginners. Mastering every aspect of this vast technology can take several months. The learning curve can be steep, especially for those unfamiliar with automated testing frameworks
- Not officially extendable via plugins — Compared to Cypress and Selenium, Playwright cannot be extended via official or community-developed plugins. This is possible only through
playwright-extra
, a community-driven project tthat adds extensibility to Playwright via several plugins - Heavy library — The
playwright
npm package has an uncompressed size of 3 MB and depends onplaywright-core
, which has an unpacked size of 7 MB. That is a total of 10 MB. On top of that, browser executables required by Playwright take hundreds of MB - No support for spies — Playwright does not have built-in support for spies, which are commonly used in unit testing to monitor function calls and their arguments. If you need such functionality, you must rely on additional libraries or frameworks
- Ongoing changes — Playwright is still under active development, with at least a couple of new releases per month, which means frequent updates and changes to the API. While this ensures access to the latest browser features and many improvements based on community feedback, it can also lead to potential instability and the need for updates in test scripts
Further reading:
Key Playwright features to know
Having seen the main strengths and weaknesses of Playwright, you’re ready to get into the specifics of what this popular automation tool can do.
Rich API
What makes Playwright such a powerful tool is its strongly typed API, which allows you to:
- Select DOM elements — Identify page elements and retrieve them by ID, name, text, and many other strategies, or by using a CSS selector or XPath expression
- Automate web interactions — Use built-in methods to simulate user interaction with web elements, including clicking, typing, dragging, and more. Playwright also supports complex interactions, such as handling file uploads and downloads
- Run custom JavaScript script — Run native JavaScript code on the page to perform interactions and actions not directly supported by Playwright methods or utilities
- Deal with modern web features — Take advantage of WebSockets, service workers, WebRTC, and other modern web and browser features. This makes it possible to thoroughly test the latest web technologies
- Take screenshots and visually compare them — Take screenshots of the entire viewport or a single element and use options like
maxDiffPixels
to compare them for visual regression testing
These are just a few of the many features supported by the rich Playwright API. Check out the official documentation for more information.
Further reading:
- WebRTC signaling with WebSocket and Node.js
- WebSockets tutorial: How to go real-time with Node and React
- Automated visual regression testing with Jest
Auto-waiting
Before performing any action on a web element, Playwright performs a series of actionability checks. These checks ensure that the action will behave as expected.
Specifically, Playwright automatically waits for all these checks to pass and only then executes the requested action. If the checks do not pass within the globally configured timeout value, the action fails with a TimeoutError
.
For example, before performing a locator.click()
action, Playwright will ensure that:
-
locator
resolves to an exactly one element - Element is visible
- Element is in a stable state (e.g. not in an animation)
- Element can receive events
- Element is enabled
If you don’t like this behavior, you can opt out of auto-waiting by specifying the force
option to false
:
element.click({ force: true })
Network and browser mocking
Playwright can mock and modify HTTP and HTTPS network traffic to API endpoints. In particular, it can mock or intercept and modify XHRs and fetch requests your frontend application makes on the browser. This is possible thanks to the page.route()
method:
test("mocks a fruit and doesn't call api", async ({ page }) => {
// mock the api call before the page navigation logic
await page.route("*/**/api/v1/fruits", async route => {
// response of the intercepted API call
const json = [{ name: "Strawberry", id: 21 }];
// return the given response
await route.fulfill({ json });
});
// navigate to the page making the request to intercept
await page.goto("https://demo.playwright.dev/api-mocking");
// assert that the Strawberry fruit is visible
await expect(page.getByText("Strawberry")).toBeVisible();
});
The above code intercepts all the frontend calls to the */**/api/v1/fruits
endpoints and mocks a custom response for them.
Playwright also supports mocking requests via HTTP Archive (HAR) files. These files contain a record of all the network requests made by the page when it’s loaded by the browser, including information about the request and response headers, cookies, content, timings, and more. You can use Plawyright to record a HAR file, update it as required, and use it to mock network requests in your tests.
Further reading:
Screenshots and videos
Playwright supports recording options to take screenshots or record videos of your tests. By default, videos are disabled but can be enabled with the global video
option. This accepts the following values:
-
"off"
—Do not record video (default value) -
"on"
— Record a video for each test -
"retain-on-failure"
— Record videos for each test, but remove all videos from successful test runs -
"on-first-retry"
— Record video only when retrying a test for the first time
Similarly, Playwright can be configured to capture screenshots after each test run by using the screenshot
option. The supported values for this option are:
-
"off"
— Do not capture screenshots (default value) -
"on"
— Capture screenshots after each test -
"only-on-failure"
— Capture screenshots after each test failure
Trace Viewer
Trace Viewer is a powerful GUI tool to explore recorded Playwright traces after a test script has run. These traces provide comprehensive insights into your automated test runs, helping you debug and optimize your tests: When you run a test with tracing enabled, Playwright collects detailed information about each operation performed. This includes network requests, screenshots, DOM snapshots, console logs, and more.
The traces are stored in an archive file that you can explore with the Trace Viewer in an interactive interface. Inside this tool, you can navigate through each action your test performed, view corresponding network activity, and examine how the page looked at any point in time.
The Trace Viewer is particularly useful for debugging a test failed in a CI/CD environment. It can help you gain a deeper understanding of test execution to quickly identify and address issues.
Device emulation
Playwright can test your web application on your current machine or emulate real devices, including mobile phones and tablets. Select a device from the list of supported ones or configure a custom device you would like to emulate by specifying values such as "userAgent"
, "screenSize"
, "viewport"
, and if it "hasTouch"
enabled.
You can also emulate the "geolocation"
, "locale"
, and "timezone"
for all tests or for a specific test, as well as set the "permissions"
to show notifications or even change the "colorScheme"
.
Consider the following configuration file for your test suite:
// import the device list
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
projects: [
{
name: "Mobile Safari",
use: {
// configure a special device
...devices["iPhone 13"],
},
},
],
});
When running a test in headed mode, this is what you’ll see in the browser window: As configured, the window browser your application is tested in has the same viewport size as an iPhone 13.
Parallelism and sharding
By default, Playwright runs tests in parallel. In detail, it launches multiple test files in parallel using different worker processes. These are operating system processes that run independently and are orchestrated by the Playwright test runner. All workers have identical environments, start their own browsers, and cannot communicate with each other.
To be executed, a test file must be first assigned to a free worker. Thus, test files are executed in parallel, but tests of a single file are run in order and within the same worker process. You can disable parallelism by setting the number of workers to 1
. Playwright also supports sharding the test suite so that you can run it on multiple machines simultaneously.
Automatic retries
Playwright supports test retries. This is a mechanism to automatically re-run a test when it fails, which is useful for detecting flaky behavior. By default, retries are disabled. When enabled, Playwright will retry failing tests multiple times until they pass or the maximum number of retries is reached.
You can configure retries in the Playwright configuration file as shown below:
import { defineConfig } from "@playwright/test";
export default defineConfig({
// give failing tests 3 retry attempts
retries: 3,
});
After you configure the retry logic, Playwright will categorize tests in the result report as follows:
-
"passed"
— Tests that passed on the first run -
"flaky"
— Tests that failed on the first run, but passed when retried -
"failed"
— Tests that failed on the first run and failed on all other retries
Further reading:
Custom reporters
Playwright reporters are tools that generate detailed logs and summaries of test runs. They provide information on test executions, highlighting successes, failures, and other relevant details. You can also use multiple reporters at the same time.
Playwright comes with several built-in reporters, each tailored for different needs. These include:
- List reporter — Prints a line for each test being run, showing detailed information about each test's progress and outcomes
- Line reporter — Produces a single line to report the last finished test and prints failures inline as they occur
- Dot reporter — Generates a single character per successful test. This is the default reporter in CI environments, useful for reducing output noise
- HTML reporter — Generates an HTML report for the test run, which can be explore as a web page in the browser. It provides a visual and interactive way to review test results
- Blob reporter — Creates detailed reports containing all information about the test run, useful for merging reports from sharded tests. The output is in a compressed format
- JSON reporter — Produces a JSON object with comprehensive information about the test run, typically written to a file for further analysis or integration with other tools
- JUnit reporter — Generates a JUnit-style XML report, often used for integration with CI systems that support JUnit reports
- GitHub reporter — Returns annotations for test failures, making it easier to identify and address issues directly within GitHub
In addition to the built-in options, Playwright allows developers to create custom reporters to fit their specific needs. You can achieve this by implementing the Reporter
interface and defining how the test results should be processed and displayed.
Test generator
Playwright offers the ability to generate tests without coding. This Codegen feature is a great way to quickly define new tests in any of the supported programming languages. When you specify the codegen option, Playwright opens two windows:
- Browser window — Where you can interact with the site or web application you want to test
- Playwright's inspector window — Where you can record, copy, and delete tests, as well as change the programming language of the generated code
Playwright will generate the code associated with the interactions you perform on the page in the browser window. Codegen can determine the recommended locator for the elements you interact with and turns all actions you make on the page into lines of code. Thanks to a special toolbar, you can also define assertions to close the generated test logic.
UI Mode
When launching a test in UI Mode, Playwright opens a window with a list of all test files in your suite: Here you can explore, run, and debug individual tests within these test files. UI Mode allows you to run actions back and forth to see what happens during each action, while on the right you can see the application being tested. This time-travel experience makes it easier to understand what a test does on the web application to debug it.
UI mode also enables you to filter tests by text, tag, or outcome. Other features available in this tool include seeing DOM element selectors, inspecting console errors, looking at network calls, and more.
Alternatives to Playwright
As powerful as Playwright is, no single tool can meet every developer's needs. Some developers may prefer a lighter library, while others may require features such as spies and full support for component testing. Similarly, some teams might look for extensibility through a large ecosystem of plugins.
Below is a table comparing Playwright with its main competitors to help you make the right choice about which browser automation tool to use:
Playwright | Selenium | Cypress | Puppeteer | |
---|---|---|---|---|
Tool type | Framework for web testing and automation | Browser automation framework and ecosystem | Front-end testing tool that runs in a browser | High-level API to control Chrome over the DevTools Protocol |
GitHub stars | 62k+ | 29k+ | 46k+ | 87k+ |
npm weekly downloads | ~5.6M | ~2M | ~5.5M | ~4M |
Setup | Simple | Complex | Simple | Simple |
Features | Several | Good amount | Several | Limited |
Supported browsers | All major modern browsers | All major browsers, including IE | Chromium-based browsers, Firefox | Chromium-based browsers, experimental Firefox support |
Supported languages | JavaScript, Python, Java, .NET languages | Java, JavaScript, C#, Python | JavaScript | JavaScript |
Built-in test runner | Yes | No | Yes | No |
Plugins | Not officially supported but available via playwright-extra | Only supported in Selenium IDE | Native support | Not officially supported but available via puppeteer-extra |
Further reading:
- Comparing the best Node.js unit testing frameworks
- Playwright vs. Puppeteer: Which should you choose?
- Cypress vs. Selenium: Why Cypress is the better option
- Cypress adoption guide: Overview, examples, and alternatives
- Comparing Next.js testing tools and strategies
Conclusion
In this article, we discussed what Playwright is and how it has become one of the most popular browser automation and testing frameworks in the industry. We explored its functionality, advantages and disadvantages, main features, and how it compares to similar testing technologies. Playwright expertise unlocked!
The aim of this overview was to assist you in evaluating Playwright for your testing suite or browser automation project. If you have any further questions about what Playwright is best for and how to use it effectively, feel free to comment below.
Get set up with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side.
NPM:
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Script Tag:
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
3.(Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
Top comments (0)