Playwright Testing Essentials: A Beginner's Guide
End-to-end (E2E) testing is a methodology used to verify whether the flow of an application is performing as designed from start to finish. This type of testing aims to simulate the effects of real user inputs on the system under test and validate that the results are as expected.
For example, an end-to-end test for an e-commerce website should cover the entire purchase process, including product page functions (like 'add to cart'), customer data validation, payment processing, successful transaction confirmation, and the accuracy of confirmation emails.
Several tools have been developed to facilitate and automate end-to-end testing in web environments, yet Playwright distinguishes itself as a particularly feature-rich, reliable, scalable, and efficient option in this domain.
In this article, we'll examine Playwright's capabilities and architecture, then explore some basic examples of automating and debugging end-to-end tests for web applications.
Let's get started!
What is Playwright?
Playwright is an open-source end-to-end test automation framework developed by Microsoft for the modern web. It allows you to write scripts that facilitate cross-browser and cross-platform web interactions using a unified API.
The framework is capable of automating a variety of browser tasks, including clicks, typing, and scrolling, as well as more intricate actions like drag-and-drop and multi-touch gestures.
Playwright supports major browser engines like Chromium, Firefox, and WebKit, and it can also emulate mobile devices to test across various screen sizes and resolutions. It runs these tests in headless mode by default for use in CI pipelines, but also supports headed and UI modes for a better development experience.
Other key features include the ability to simulate different user interactions, intercept network traffic to analyze application behavior under various conditions, and capture screenshots and videos for debugging and visual regression tests.
At the time of writing, Playwright's API is compatible with JavaScript, TypeScript, Python, .NET (C#), and Java, and it fully supports Debian-based Linux distributions (like Ubuntu), macOS, and Windows.
Use cases of Playwright
The capabilities of Playwright make it immensely useful in many scenarios, particularly when developing and testing web applications. Some common Playwright use cases include:
1. Test automation
With Playwright, you can automate user interactions in a web application to validate its functionality and performance. This includes testing user flows, form submissions, and multi-page navigation.
You can also use it for regression testing to ensure new updates work as expected without breaking existing functionality. Since the test suite runs on the three major browser engines, you can easily verify that your applications work consistently across different browsers and platforms.
Playwright's mobile emulation capabilities are also helpful for testing UI responsiveness and UX consistency across devices. It can also assess web app performance, responsiveness, and accessibility to verify compliance with accepted standards.
2. Web scraping
For web scraping, Playwright offers a robust solution that comes in handy where conventional tools are inadequate.
By operating like a real browser, it can scrape data from sites that dynamically load content using client-side JavaScript. This makes it effective for extracting information from modern, interactive websites.
Despite some websites employing anti-scraping measures like CAPTCHAs or authentication, Playwright can often navigate these obstacles by mimicking human interactions more accurately than traditional scraping techniques.
3. Automating repetitive web tasks
Another significant use case of Playwright is its ability to automate repetitive web tasks, which could help save time and improve efficiency in various scenarios. For example, you can automate data entry or form submissions, routine administrative tasks, and many other repetitive actions.
It even offers a feature where you can record the actions in your browser to a Playwright script file, and then run it on schedule or as needed.
A key feature of Playwright in these scenarios is its ability to interact with web pages as a real user would, which makes complex user interactions automatable.
Understanding Playwright's architecture
Playwright's architecture is closely aligned with modern browsers and operates out-of-process, avoiding the limitations of in-process test runners like Cypress. It uses a WebSocket connection for bi-directional client-server communication, which is faster and more efficient than communicating over HTTP.
Here's a concise breakdown:
Client: Playwright provides API bindings for interacting with the Playwright framework in various programming languages. These APIs provide a set of high-level commands which are translated into concise browser actions.
Server: The Playwright Node.js server is what facilitates communication between the client scripts and supported browser engines.
Client-server communication: For each script, Playwright establishes a low-latency WebSocket-based communication channel over a single TCP connection between the client and server that remains in place until the test is completed.
Since commands are sent on a single connection, chances of test failure or flakiness is reduced, and commands are executed much quicker than in alternative tools which use HTTP connection idioms.
Getting started with Playwright
Now that you have a better understanding of what Playwright is and what it can do, we'll proceed to get a feel of how it works for the remainder of this article.
For a new project, use this command to install Playwright and its dependencies:
npm init playwright@latest <project_dir>
For example:
npm init playwright@latest playwright-tutorial
In an existing project, navigate to the root directory and run without
<project_dir>
:
npm init playwright@latest
During setup, choose these options:
Initializing project in 'playwright-tutorial'
✔ Do you want to use TypeScript or JavaScript? · JavaScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false
✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) · true
✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo npx playwright install-deps')? (y/N) · true
Once these options are selected, the installation process will continue until the necessary components, including Chromium, Firefox, and WebKit browser engines are downloaded.
Once the installation is done, explore the new project directory:
cd playwright-tutorial
tree -I node_modules
You'll see the directory's contents with node_modules
excluded:
.
├── package.json
├── playwright.config.js
├── package-lock.json
├── test-results
├── tests
│ └── example.spec.js
└── tests-examples
└── demo-todo-app.spec.js
In playwright.config.js
, you'll find the configuration for Playwright,
including the selected browsers for tests. The tests
folder contains a basic
test to verify that Playwright is set up correctly, while tests-examples
provides more detailed example tests for a todo app.
The anatomy of a Playwright test
To understand how Playwright tests work, let's look at the sample test provided
in the initial setup. Open tests/example.spec.js
in your editor:
code tests/example.spec.js
// @ts-check
const { test, expect } = require('@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();
});
This script consists of two test cases to validate certain aspects of Playwright's documentation website.
The first test is named has title
, and it navigates to
https://playwright.dev/
using the page.goto()
method (similar to entering a
URL in the browser).
The expect()
method is subsequently used to make assertions on the page's
contents and attributes. Here, /Playwright/
is a regular expression pattern,
and toHaveTitle()
asserts that the contents of the page's <title>
tag
matches this pattern.
In the second test, the Playwright homepage is also visited. Once the page loads, the GET STARTED link is located and clicked.
The resulting page is then asserted to have an Installation heading that is visible on the page.
The screenshots above demonstrate that the page and its interactions align with the requirements of both tests. However, to confirm their effectiveness, we must execute the tests through Playwright as detailed in the following section.
Running Playwright tests
To execute your test scripts, use the playwright test
command. It runs all the
scripts in the tests
folder across all browsers specified in the
playwright.config.js
file.
By default, tests are conducted in headless mode, which means that no browser window is opened and the outcomes are displayed in the terminal.
npx playwright test
Running 6 tests using 6 workers
6 passed (20.1s)
To open last HTML report run:
npx playwright show-report
The output shows six tests passing because both tests in the
tests/example.spec.js
run in Chromium, Firefox, and WebKit respectively as
specified in the projects
key of your playwright.config.js
file:
. . .
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
. . .
],
. . .
The tests were also executed concurrently using six worker processes. Each of these workers represent a separate OS process, all equipped with identical environments.
Before exploring the test results, let's take a look at some options available for running tests.
Running specific test scripts
To run specific test files among many, specify the desired files like this:
npx playwright test <file1> <file2> . . .
You can also run all the tests contained in different directories like this:
npx playwright test tests/<dir1>/ tests/<dir2>/
Running a subset of your tests
Run tests matching a regular expression with the -g
flag. For instance, to
execute only the has title
test, run:
npx playwright test -g 'has title'
Running tests in certain browsers
Use the --project
flag to run tests on specified browsers, matching the name
in your Playwright config's projects
array.
npx playwright test --project 'chromium' 'firefox' # only run the tests in Chromium and Firefox
Running tests in headed mode
By default, Playwright tests run in headless mode to improve execution speed and
compatibility with server environments. To watch the tests in a browser UI, use
the --headed
flag.
For example, combine --headed
with --project
to see tests in the Chromium
browser:
npx playright test --headed --project 'chromium'
The browser will open, run the tests, and close afterward.
Examining Playwright test results
Once a test run is completed, an HTML report is saved in the playwright-report
directory. Open it with the following command:
npx playwright show-report
Serving HTML report at http://localhost:9323. Press Ctrl+C to quit.
This report, accessible at http://localhost:9323
, should launch in your
default browser. It displays all test cases, their results in the different
browsers, and their execution times. The report allows filtering by status or
searching for specific tests.
To demonstrate a test failure, alter your has title
test like so:
const { test, expect } = require('@playwright/test');
test('has title', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Wikipedia/);
});
This change will cause a failure, as the Playwright homepage title doesn't
include Wikipedia
. Run the test:
npx playwright test
The test report automatically opens in your default browser when a failure is detected:
If you click on the failing test, you'll see more details such as the execution times for each action and the action that lead to the failure.
In this case, the test fails due to the mismatch between the expected and actual title.
Debugging Playwright tests
To conclude this article, let's examine how to debug Playwright tests using the
Playwright Inspector. To engage the Inspector for test runs, use the --debug
flag:
npx playwright test --debug
For example, let's debug the get started link
test in Chromium alone by
combining the --project
and -g
flags as follows:
npx playwright test --debug --project=chromium -g 'get started'
This will open both a Chromium browser and the Playwright Inspector window. Initially, the test is paused, so the browser window appears blank.
To move to the next action in the test, you can press F10
or click the Step
over button. You'll see the current action highlighted in the test code, and
matching elements highlighted in the browser window.
You'll have to repeat this for as many actions in the test until you get to the debugging point.
If your test contains many actions, you can add the page.pause()
method to
pause it just before the action you're interested in. For instance, to pause
after clicking the 'Get started' link but before the assertions, you can write:
. . .
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();
await page.pause();
// Expects page to have a heading with the name of Installation.
await expect(
page.getByRole('heading', { name: 'Installation' })
).toBeVisible();
});
With this, the test initially pauses, but you can jump directly to the
page.pause()
line by pressing F8
or the Resume button.
Without page.pause()
, resuming runs the test to completion.
While paused, use the Pick locator tool to select any page element. The code for the element will appear in the Locator tab.
Playwright uses a unique combination of values to identify the target element so it's safe to copy the locator and use it in your tests as is.
Final thoughts
In this article, we only focused on Playwright's basic test automation capabilities and how you can get started with running and debugging test scripts.
In the next article, you'll automate the end-to-end testing of a web application and learn many of Playwright's advanced features along the way.
Thanks for reading, and happy coding!
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for usBuild on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github