Learn Playwright in 10 DaysDay 8: Debugging and Tracing

Day 8: Debugging and Tracing

What You'll Learn Today

  • Headless vs headed mode
  • Playwright Inspector (--debug flag, page.pause())
  • UI Mode (--ui flag)
  • Trace Viewer: recording and viewing traces
  • Screenshots on failure
  • Video recording
  • Console log capturing
  • Slow motion mode
  • VS Code extension debugging
  • Common debugging strategies

Headless vs Headed Mode

By default, Playwright runs in headless mode (no browser window displayed). When you need to visually observe what your test is doing, switch to headed mode.

# Default (headless)
npx playwright test

# Show the browser window (headed)
npx playwright test --headed

You can also set this permanently in playwright.config.ts:

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

export default defineConfig({
  use: {
    headless: false, // Always show browser
  },
});

Tips: Use headless mode in CI environments and headed mode during local development.


Playwright Inspector

The Playwright Inspector is an interactive debugging tool that lets you step through your test actions one by one while inspecting the page state.

The --debug Flag

# Debug all tests
npx playwright test --debug

# Debug a specific test file
npx playwright test tests/login.spec.ts --debug

# Start debugging from a specific line
npx playwright test tests/login.spec.ts:15 --debug

When you use the --debug flag, the following happens:

  1. The browser launches in headed mode
  2. The Playwright Inspector window opens
  3. The test pauses at the first action
  4. You can use "Step Over" and "Resume" buttons to control execution

page.pause()

You can insert breakpoints anywhere in your test code.

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

test('checkout flow', async ({ page }) => {
  await page.goto('https://example.com/shop');
  await page.getByRole('button', { name: 'Add to Cart' }).click();

  // Pause here and inspect with the Inspector
  await page.pause();

  await page.getByRole('button', { name: 'Checkout' }).click();
  await expect(page.getByText('Order confirmed')).toBeVisible();
});

The Inspector window provides the following capabilities:

Feature Description
Step Over Advance to the next action
Resume Run until the next pause() or test end
Record Record browser interactions as code
Pick Locator Select an element to generate a locator

UI Mode

UI Mode is an integrated tool for running, monitoring, and debugging tests in a single interface.

npx playwright test --ui

Key features of UI Mode include:

  • Test list: Displays all test files and test cases
  • Watch mode: Automatically re-runs tests when files change
  • Timeline: Shows each test step in a timeline view
  • DOM snapshots: Inspect the DOM state at each step
  • Network log: View all requests and responses
  • Filtering: Filter by test name, file name, or status
flowchart LR
    subgraph UIMode["UI Mode"]
        A["Test List"]
        B["Timeline"]
        C["DOM Snapshots"]
        D["Network Log"]
    end
    A --> B --> C
    B --> D
    style UIMode fill:#3b82f6,color:#fff

Tips: UI Mode is the most convenient debugging tool for day-to-day development. Keep it running while writing and modifying tests.


Trace Viewer

The Trace Viewer lets you record a complete trace of your test execution and replay it later for analysis. It is especially useful for investigating CI failures.

Configuring Trace Recording

Set the trace recording behavior in playwright.config.ts:

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

export default defineConfig({
  use: {
    trace: 'on-first-retry', // Recommended: record only on retry
  },
});

Here is a comparison of the available options:

Value Behavior Use Case
'off' No trace recording Default
'on' Always record traces Debugging
'on-first-retry' Record on first retry Recommended for CI
'retain-on-failure' Retain only on failure Recommended for CI

Per-Test Trace Configuration

You can enable tracing for specific tests only.

test('complex checkout flow', async ({ page, context }) => {
  // Record trace for this test only
  await context.tracing.start({ screenshots: true, snapshots: true });

  await page.goto('https://example.com/checkout');
  await page.getByLabel('Card Number').fill('4242424242424242');
  await page.getByRole('button', { name: 'Pay' }).click();

  await context.tracing.stop({ path: 'checkout-trace.zip' });
});

Viewing Traces

There are two ways to view recorded traces:

# Launch the local Trace Viewer
npx playwright show-trace test-results/trace.zip

# Or use the browser-based viewer
# Drag and drop the zip file onto trace.playwright.dev

The Trace Viewer provides the following information:

  • Action log: Every action executed (click, fill, goto, etc.)
  • Screenshots: Before/after screenshots for each action
  • DOM snapshots: The DOM structure at each point in time
  • Network: All HTTP requests and responses
  • Console: Browser console output
  • Source code: Mapping to the corresponding test code

Screenshots on Failure

Capturing screenshots when tests fail helps quickly identify the root cause.

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

export default defineConfig({
  use: {
    screenshot: 'only-on-failure', // Capture only on failure
  },
});
Value Behavior
'off' No screenshots
'on' Capture after every test
'only-on-failure' Capture only on failure (recommended)

You can also take screenshots manually within tests:

test('visual check', async ({ page }) => {
  await page.goto('https://example.com');

  // Full page screenshot
  await page.screenshot({ path: 'screenshots/homepage.png' });

  // Element screenshot
  await page.getByRole('navigation').screenshot({
    path: 'screenshots/navbar.png',
  });

  // Full page including scrolled content
  await page.screenshot({
    path: 'screenshots/full-page.png',
    fullPage: true,
  });
});

Video Recording

You can record the entire test execution as a video.

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

export default defineConfig({
  use: {
    video: 'retain-on-failure', // Keep video only on failure
  },
});
Value Behavior
'off' No video recording
'on' Always record
'retain-on-failure' Keep only on failure (recommended)
'on-first-retry' Record on first retry

You can also specify the video dimensions:

export default defineConfig({
  use: {
    video: {
      mode: 'retain-on-failure',
      size: { width: 1280, height: 720 },
    },
  },
});

Tips: Video recording impacts test execution speed. In CI, use 'retain-on-failure' to only retain videos when needed.


Console Log Capturing

You can capture browser console output in your tests to check for application errors and debug information.

test('capture console logs', async ({ page }) => {
  // Collect console messages
  const logs: string[] = [];
  page.on('console', (msg) => {
    logs.push(`[${msg.type()}] ${msg.text()}`);
  });

  // Detect errors
  const errors: string[] = [];
  page.on('pageerror', (error) => {
    errors.push(error.message);
  });

  await page.goto('https://example.com');
  await page.getByRole('button', { name: 'Submit' }).click();

  // Verify no JavaScript errors occurred
  expect(errors).toHaveLength(0);

  // Output logs for debugging
  console.log('Browser logs:', logs);
});

You can also monitor failed network requests:

test('monitor failed requests', async ({ page }) => {
  const failedRequests: string[] = [];

  page.on('requestfailed', (request) => {
    failedRequests.push(`${request.method()} ${request.url()}`);
  });

  await page.goto('https://example.com');

  // Verify no requests failed
  expect(failedRequests).toHaveLength(0);
});

Slow Motion Mode

Slow motion lets you watch your test actions play out at a reduced speed, making it easier to observe what is happening.

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

export default defineConfig({
  use: {
    launchOptions: {
      slowMo: 500, // 500ms delay between each action
    },
  },
});

You can also enable debug mode temporarily from the command line:

# Combine with headed mode for best results
PWDEBUG=1 npx playwright test --headed

Tips: slowMo is a browser-level option, so it adds a delay to every action (clicks, typing, navigation). Use it only for debugging purposes.


VS Code Extension Debugging

The Playwright Test for VS Code extension enables you to debug tests directly within VS Code.

Setup

  1. Install the "Playwright Test for VS Code" extension
  2. Open a test file
  3. A play button appears next to each test name

Debugging Features

flowchart TB
    subgraph VSCode["VS Code Playwright Extension"]
        A["Set Breakpoints"]
        B["Step Execution"]
        C["Inspect Variables"]
        D["View Browser"]
    end
    A --> B --> C
    B --> D
    style VSCode fill:#8b5cf6,color:#fff

Key features of the VS Code extension:

Feature Description
Run Test Execute a single test
Debug Test Run with breakpoints
Show Browser Display the browser during test execution
Pick Locator Select an element in the browser to generate a locator
Record New Generate a new test from browser interactions
Watch Mode Automatically re-run on file save

Debugging with Breakpoints

  1. Click to the left of a line number to set a breakpoint
  2. Click the "Debug Test" button next to the test name
  3. Execution pauses at the breakpoint
  4. Inspect variable values and step through the code

Common Debugging Strategies

1. Progressive Narrowing

When a test fails, investigate in the following order:

flowchart TB
    A["Test Failure"] --> B["Check Error Message"]
    B --> C["Check Screenshot"]
    C --> D["Check Trace"]
    D --> E["Interactive Debug with page.pause()"]
    E --> F["Root Cause Found & Fixed"]
    style A fill:#ef4444,color:#fff
    style F fill:#22c55e,color:#fff

2. Isolating Tests

Run only the problematic test for efficient debugging.

# Run a specific test file
npx playwright test tests/checkout.spec.ts

# Filter by test name
npx playwright test -g "should complete checkout"

# Run only a specific browser project
npx playwright test --project=chromium

3. CI Debugging Configuration

Since interactive debugging is not possible in CI, ensure rich artifacts are available.

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

export default defineConfig({
  // Retry configuration
  retries: process.env.CI ? 2 : 0,

  use: {
    // Debugging artifacts for CI
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
});

4. Common Issues and Solutions

Issue Cause Solution
Element not found Incorrect locator Use Pick Locator to regenerate
Timeout Element loads slowly Adjust expect timeout
Flaky test Async race condition Add waitForLoadState()
Fails only in CI Environment differences Save traces as CI artifacts

Summary

Let's review the key debugging and tracing tools covered today.

Tool / Feature Purpose How to Use
Headed mode Visually observe browser actions --headed
Playwright Inspector Step-through interactive debugging --debug / page.pause()
UI Mode Integrated debugging environment --ui
Trace Viewer Record and replay test execution trace: 'on'
Screenshots Capture page state on failure screenshot: 'only-on-failure'
Video Record full test as video video: 'retain-on-failure'
Console capture Capture browser logs page.on('console', ...)
Slow motion Delayed action playback slowMo: 500
VS Code extension In-IDE debugging Install extension

For CI environments, the recommended combination is trace: 'on-first-retry', screenshot: 'only-on-failure', and video: 'retain-on-failure'. For local development, make --ui mode part of your daily workflow.


Next up: In Day 9, we'll explore "Parallel Execution and Performance." You'll learn how to optimize test execution speed and efficiently manage large test suites.