# 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](https://playwright.dev/) 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!

[ad-uptime]

## What is Playwright?

![Screenshot from 2024-01-28 17-12-24.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/a05698aa-8038-45e1-1bb5-c7a8d93dc800/orig =2672x1662)

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.

![playwright-ui-mode.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/0ebfb99f-3c2d-483f-ad84-666ca1630900/lg1x =2804x1918)

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](https://betterstack.com/community/guides/linux/cron-jobs-getting-started/)
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:

```command
npm init playwright@latest <project_dir>
```

For example:

```command
npm init playwright@latest playwright-tutorial
```

In an existing project, navigate to the root directory and run without
`<project_dir>`:

```command
npm init playwright@latest
```

During setup, choose these options:

```text
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
```

![playwright-init.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/1d29cc85-86df-4ef0-dc25-7ecdd63d7a00/md1x =2330x1250)

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:

```command
cd playwright-tutorial
```

```command
tree -I node_modules
```

You'll see the directory's contents with `node_modules` excluded:

```text
[output]
.
├── 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:

```command
code tests/example.spec.js
```

```javascript
[label 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](https://playwright.dev).

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.

![playwright-website-title.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/b30f3461-2543-432b-655b-b080969a7300/public =2282x1232)

In the second test, the Playwright homepage is also visited. Once the page
loads, the **GET STARTED** link is located and clicked.

![playwright-getting-started.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/f41f6b26-b243-4b48-fae0-bb80d18e9b00/md2x =2282x1354)

The resulting page is then asserted to have an **Installation** heading that is
[visible](https://playwright.dev/docs/actionability#visible) on the page.

![playwright-installation-heading.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/037b4ee3-ffd3-4f92-1521-4c670fa31a00/md2x =2282x1354)

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.

```command
npx playwright test
```

```text
[output]
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:

```javascript
[label playwright.config.js]
. . .
  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:

```command
npx playwright test <file1> <file2> . . .
```

You can also run all the tests contained in different directories like this:

```command
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:

```command
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.

```command
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:

```command
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:

```command
npx playwright show-report
```

```text
[output]
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.

![Screenshot 2024-01-19 at 10-44-28 Playwright Test Report.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/287e81c1-196b-4162-49dd-536083947f00/md2x =1214x546)

To demonstrate a test failure, alter your `has title` test like so:

```javascript
[label tests/example.spec.js]
const { test, expect } = require('@playwright/test');

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
[highlight]
  await expect(page).toHaveTitle(/Wikipedia/);
[/highlight]
});
```

This change will cause a failure, as the Playwright homepage title doesn't
include `Wikipedia`. Run the test:

```command
npx playwright test
```

The test report automatically opens in your default browser when a failure is
detected:

![Screenshot from 2024-01-19 11-06-35.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/418da1ea-bf42-49c2-ef50-1b392ab7ff00/lg2x =2322x1352)

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:

```command
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:

```command
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.

![playwright-debug.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/4301e826-2281-40fb-29e8-e86e9e670400/md2x =2450x1484)

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.

![playwright-debug-2.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/8d02c87f-a69f-49bb-2132-d9a0842c1700/lg2x =2460x1504)

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:

```javascript
[label tests/example.spec.js]
. . .

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();

[highlight]
  await page.pause();
[/highlight]

  // 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.

![playwright-debug-3.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/81886890-e749-400b-02d5-b906b94cc100/lg1x =2452x1488)

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-debug-4.png](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/2aebdda4-2e6b-48b3-3a17-1fb149165100/lg2x =2452x1488)

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!