Playwright E2E testing for frontend developers, part 1 - traces and GitHub Actions CI

In front-end development, end-to-end (E2E) testing, which verifies an entire application including UI behavior, is becoming increasingly important. However, the difficulty of introducing and operating E2E tests may keep some teams from putting them into practice.

This article is split into two parts and explains the process of introducing and using E2E testing with Playwright, using a simple web application as the example.

In Part 1, we covered how to set up Playwright, how to write basic test code, and how to run tests. In this second part, we will look at Playwright’s tracing feature, which helps identify why a test failed. We will also cover how to run tests automatically in a CI environment.

Who this article is for

  • Readers who understand the basics of Playwright and want to move to the next step
  • Developers who want to integrate Playwright into team development or a CI environment

After reading this article, you will be able to

  • Use tracing to analyze why a test failed
  • Integrate Playwright with GitHub Actions and run E2E tests automatically in CI

The project containing the test code used in this article is available below. You can run it locally, so try it out.

First, let’s look at Trace Viewer, which is useful for identifying the cause of test failures.

Trace Viewer

Trace Viewer is a feature that helps with debugging when a test fails. The operations performed during the test, network requests, and screenshots are recorded as a trace, allowing you to reproduce later what the test did and where it failed.

Add trace settings to playwright.config.ts. If you also add reporter settings, an HTML report will be generated, making it easy to access Trace Viewer for each test.

playwright.config.ts

import {defineConfig, devices} from '@playwright/test';

export default defineConfig({
  // ... (omitted)

  // Generate an HTML report. If a test fails, open it automatically after the test run.
  reporter: [['html', { open: 'on-failure' }]],
  use: {
    // ... (omitted)
    
    // In this article, tracing is always enabled ('on') for verification.
    // In production, use 'retain-on-failure' (save only on failure) or,
    // in CI, 'on-first-retry' (save only on retry).
    trace: 'on',
  },
  // ... (omitted)
});

Now reports and traces are generated when tests run. To check how this works, intentionally change the test so that it fails, then run it.

tests/app.spec.ts

import {expect, test} from '@playwright/test';

test('the counter button increments when clicked', async ({page}) => {
  await page.goto('/');
  // Get the button Locator
  const counter = page.getByRole('button', {name: 'count is'});
  // Assert the Locator text
  await expect(counter).toHaveText('count is 0');
  // Operate on the Locator
  await counter.click();
  // Assert the Locator text
  await expect(counter).toHaveText('count is 2'); // Change the expected value from 1 to 2 to intentionally fail the test
});

▼Run the command added to npm scripts ("e2eTest": "playwright test")

npm run e2eTest

When the test fails, the report opens automatically. The failed tests are shown in a list. When you select the target test, you can see the error details and a link to Trace Viewer.

Select [View Trace] to launch Trace Viewer and reproduce the test’s operation history. You can check which operation failed, along with network request results, screenshots, and other details.

▼Generate an HTML report with the reporter. You can get an overview of the test results.

Opening the report

▼Select the failed test in the report to check the error location.

Checking the test error in the report

▼Check the detailed operation history in Trace Viewer. You can replay operations and inspect screenshots and network requests.

Opening Trace Viewer

To open the report manually later, run the following command.

▼Run from the console

npx playwright show-report

Traces are saved under test-results. A directory is created for each test, and trace.zip is generated inside it. You can also open Trace Viewer directly with the following command, without going through the report.

▼Run from the console. Replace ... with the actual generated directory name.

npx playwright show-trace test-results/.../trace.zip

The show-trace command is also useful when reproducing a trace.zip from a failed CI test, covered later, on your local machine.

One of Playwright’s major strengths is that even when a test fails, you can visualize why it failed.

CI integration with GitHub Actions

By combining Playwright with CI, you can run E2E tests automatically whenever changes are made. Running tests for each pull request provides the following benefits.

  • Reduces the amount of manual checking, leaving more time for review and implementation
  • Detects bugs early, while the cost of fixing them is still low
  • Makes it easier to understand the impact on existing features, so changes can be made with confidence

This article uses GitHub Actions as the example. You can run GitHub Actions by adding a YAML file to the .github/workflows directory in your GitHub repository.

.github/workflows/playwright.yml: a minimal workflow example

name: Playwright E2E tests

on: pull_request

jobs:
  e2e:
    name: Playwright browser E2E tests
    runs-on: ubuntu-latest

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Set up Node.js
        uses: actions/setup-node@v6
        with:
          node-version: lts/*

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run E2E tests
        run: npx playwright test

      - name: Upload test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: Playwright_test_report
          path: playwright-report/

      - name: Upload test traces
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: Playwright_test_traces
          path: test-results/

The on: pull_request setting makes this workflow run for pull requests. As shown in steps, it runs the following processes in order.

  1. Check out the repository
  2. Set up Node.js
  3. Install dependencies
  4. Install Playwright browsers
  5. Run the E2E tests
  6. Upload the test report if one was created
  7. Upload the test traces if they were created

The main action you want is step 5, running the tests. Before that, steps 1 to 4 are required as preparation. GitHub Actions runs in a clean environment, so Node.js, dependencies, and browsers must be installed each time.

Steps 6 and 7 upload the test report and traces to GitHub Actions. By downloading the saved files, you can inspect the detailed test results later.

Whether test reports and traces are generated depends on the settings in playwright.config.ts. Configure appropriate values in advance. If you want to enable them only when running in CI, use the CI environment variable.

▼Branch the playwright.config.ts settings when running in CI

import {defineConfig, devices} from '@playwright/test';

// GitHub Actions sets CI=true when it runs
const isCI = !!process.env.CI;

export default defineConfig({
  // ... (omitted)
  
  use: {
    // ... (omitted)
    
    // In CI, save traces only when a test fails. Locally, always enable traces.
    trace: isCI ? 'retain-on-failure' : 'on',
  },
  // ... (omitted)
});

You can check a pull request where GitHub Actions actually ran and the E2E test failed below.

▼Create a pull request after changing the code so the test fails. You can confirm that GitHub Actions failed.

GitHub Actions failing on a pull request

▼Check the details of the failed GitHub Actions run.

Details of the failed GitHub Actions run

▼Because trace.zip is saved as a GitHub Actions artifact, you can download it and inspect it locally in Trace Viewer.

Downloadable trace.zip generated by the test

Note: ZIP files downloaded from GitHub Actions must be extracted before use.

  • For the test report (Playwright_test_report.zip), pass the extracted directory to the npx playwright show-report <report-directory-path> command.
  • For the test traces (Playwright_test_traces.zip), pass the trace.zip file inside the extracted directory to the npx playwright show-trace <trace.zip-file-path> command.

By integrating Playwright into CI, tests run automatically whenever changes are made, making it easier to check the impact on existing features. This improves development efficiency and helps detect bugs early. Consider integrating Playwright into your CI environment as well.

Column: Playwright in the AI era

Playwright is also making progress in integrations with AI agents. Implementations that support the CLI and MCP are available, allowing browser operations and test execution to be controlled from AI.

In the future, combining Playwright with AI may become one of the options for test operation. If you are interested in using Playwright with AI, check out the related repositories below.

  • Playwright CLI: A tool for running Playwright from the command line to control browser operations and tests. It can also be used from AI agents.
  • Playwright MCP: An implementation that supports MCP, a standard for connecting AI tools with external tools.

Conclusion

In this second part, we covered how to debug with Playwright’s tracing feature and how to integrate Playwright with CI using GitHub Actions.

Tests are not something you write once and leave behind. What matters is being able to analyze failures and run tests continuously. Use traces to investigate the cause of failures, and run tests every time through CI. With this flow in place, E2E testing becomes a system that naturally supports day-to-day development.

Together with Part 1, this should give you a complete overview of the basics and operation of E2E testing with Playwright. Try introducing it into your own project.

Share on social media
Your shares help us keep the site running.
Post on X
Share
Copy URL
KAWAKATSU Kentaro

Interactive developer. Constantly exploring game technologies, GPUs, and related fields. His primary transportation around home is a bicycle.

Articles by this staff