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:
- The browser launches in headed mode
- The Playwright Inspector window opens
- The test pauses at the first action
- 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:
slowMois 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
- Install the "Playwright Test for VS Code" extension
- Open a test file
- 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
- Click to the left of a line number to set a breakpoint
- Click the "Debug Test" button next to the test name
- Execution pauses at the breakpoint
- 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.