End-to-End Testing with Playwright

Playwright makes End-to-End testing simple!


Playwright for End-to-End Testing

Playwright is a versatile tool designed for end-to-end testing, offering an intuitive API and streamlined workflows that simplify and accelerate the process of writing tests. With support for all modern rendering engines and the ability to run tests across multiple platforms, Playwright integrates seamlessly into both local environments and CI/CD pipelines. Its ease of use and robust features make it an excellent choice for engineers looking to optimize their testing processes.

To get started, initialize Playwright with:

npm init playwright@latest

This command sets up a basic Playwright project, including a playwright.config file where you can configure testing preferences, such as browser choice, parallel execution, and headless mode (by default).


Writing Tests with Playwright

Playwright tests are structured around three main steps: setting up the environment, performing actions, and asserting outcomes. Understanding the anatomy of a Playwright test is essential for writing effective tests.

Anatomy of a Playwright Test

Playwright tests typically consist of:

  1. Setup: Prepare the environment by navigating to a page or initializing the test state.
  2. Action: Interact with the webpage using Playwright’s APIs, such as clicking buttons or filling forms.
  3. Assertion: Verify the results by asserting the expected behavior, like checking if an element is visible or contains specific text.

The Locator API is vital during the "Action" phase. It precisely targets elements on the page, automatically waiting for them to be ready before performing any action. This reduces flaky tests by handling elements' visibility, stability, and readiness.

Here’s an example of a basic Playwright test:

import { test, expect } from '@playwright/test';
 
test('view my blog link', async ({ page }) => {
  // Step 1: Navigate to the page
  await page.goto('https://timgentry.dev/');
 
  // Step 2: Click the "View my Blog" link
  await page.getByRole('link', { name: 'View my Blog' }).click();
 
  // Step 3: Verify the heading named "Blog" is visible
  await expect(page.getByRole('heading', { name: 'Blog' })).toBeVisible();
});

In this example, methods like getByRole() from the Locator API ensure reliable identification of elements before interacting with them.

Key Components of a Playwright Test

  1. Test Name: Each test begins with a descriptive name, followed by an asynchronous function containing the test logic.
  2. Page Object: The page object represents a browser page or tab, used for navigation and interactions.
  3. Actions: Playwright interacts with elements on the page through the locator API, ensuring elements are actionable before performing actions like clicks or form submissions.
  4. Assertions: Tests use the expect function to validate outcomes, ensuring the page behaves as expected.

Some common actions in Playwright include:

ActionDescription
locator.click()Click an element.
locator.fill()Fill a text input.
locator.check()Check a checkbox.
locator.hover()Hover over an element.
locator.setInputFiles()Upload files.

Assertions in Playwright

Playwright provides built-in assertions via the expect function. These assertions check various conditions, such as element visibility, attribute values, and page titles. Playwright also includes async matchers that wait for conditions to be met before proceeding, ensuring reliable, non-flaky tests.

Examples of common assertions:

AssertionDescription
expect(locator).toBeVisible()Ensure an element is visible.
expect(locator).toHaveText()Assert that an element contains text.
expect(page).toHaveURL()Verify the page has a specific URL.

Generating Tests with Codegen

Playwright’s codegen is a fantastic tool that automates the creation of tests by recording your actions as you interact with a browser. It simplifies the test-writing process by automatically generating scripts based on real user behavior, drastically reducing the time needed to write them. To use codegen, simply run the command followed by the target URL:

npx playwright codegen https://example.com

When codegen starts, Playwright launches a browser and opens a recording session in the Playwright Inspector. As you interact with the browser (e.g., clicking buttons, filling forms, navigating pages), Playwright records these actions and translates them into code, making it easy to create repeatable tests based on actual user flows.

Here’s an example of the code generated from a simple interaction:

import { test, expect } from '@playwright/test';
 
test('example test', async ({ page }) => {
  // Navigate to the page
  await page.goto('https://example.com');
  
  // Perform a click action
  await page.click('text="Sign In"');
  
  // Fill a form field
  await page.fill('input[name="username"]', 'user123');
  
  // Submit the form
  await page.click('button[type="submit"]');
  
  // Assert a result
  await expect(page).toHaveURL('https://example.com/dashboard');
});

Benefits of Codegen

  1. Speed and Efficiency: Codegen drastically reduces the time required to write tests. By recording actions, it eliminates the need to figure out how to interact with elements on the page manually, especially when dealing with complex locators.

  2. Accurate Locators: It generates precise element selectors using Playwright’s advanced locator strategies like getByRole() and getByText(), ensuring that the generated tests are both readable and reliable.

  3. Editable Output: The generated script serves as a base, which can be refined and customized. For example, you can add more assertions, modify actions, or adjust the structure to fit test requirements.


Running and Debugging Tests

Playwright offers several options for running and debugging tests:

  • Running Tests: Use npx playwright test to execute your tests. They will run in headless mode by default, or with a visible browser using the --headed flag.
  • UI Mode: Playwright’s UI mode allows for an interactive debugging experience, with the ability to inspect logs, trace through test execution, and time-traveling.
  • Trace Viewer: Playwright can capture traces, allowing you to inspect each step of a test, including screenshots and network requests, after the test has run.

Fixtures and Reporters

Fixtures

Playwright uses fixtures to isolate the environment for each test, ensuring clean states between test runs. Common fixtures include:

  • page: A new browser page instance for each test.
  • context: Isolated browser context for each test.

Reporters

Playwright includes several reporters for test results, including a detailed HTML Reporter and CI-integrated options like JUnit. These reports help developers monitor test outcomes and troubleshoot failures.


API Testing

Playwright supports testing APIs directly using the APIRequestContext, which allows you to send HTTP requests without needing to load a webpage. This feature is useful for testing server-side APIs, preparing the server state before running UI tests, or verifying server conditions after performing browser actions.

Example: Testing an API with Playwright

import { test, expect, request } from '@playwright/test';
 
test('Create a new issue via API', async ({ request }) => {
  // Prepare the data for the new issue
  const issueData = {
    title: "API Test Issue",
    body: "This issue was created via Playwright API testing",
    labels: ["bug", "urgent"]
  };
 
  // Send a POST request to create a new issue
  const response = await request.post('https://api.example.com/issues', {
    data: issueData
  });
 
  // Validate the response status
  expect(response.ok()).toBeTruthy();
  
  // Check that the issue was created successfully
  const responseData = await response.json();
  expect(responseData.title).toBe(issueData.title);
});

Continuous Integration

Playwright integrates seamlessly with CI/CD pipelines like GitHub Actions, Azure DevOps, or Jenkins. Its JUnit reporter is ideal for continuous integration pipelines, and Playwright can be easily set up to run tests on CI servers or within Docker containers for consistent environments.


Conclusion

Playwright is a powerful tool for end-to-end testing modern web applications. Its support for automatic waits, cross-browser testing, parallel execution, and built-in debugging tools make it a valuable asset for developers aiming to create reliable and efficient tests.