Table of contents

How to Use Playwright's Trace Viewer for Debugging Failed Tests

Playwright's trace viewer is a powerful debugging tool that provides a visual timeline of your test execution, making it easier to identify why tests fail. This comprehensive guide will show you how to enable tracing, capture traces, and use the trace viewer effectively to debug your Playwright tests.

What is Playwright's Trace Viewer?

The trace viewer is a GUI tool that allows you to explore recorded Playwright traces. It provides a timeline view of your test execution, showing actions, screenshots, network requests, and console logs. This makes it invaluable for debugging complex test scenarios and understanding exactly what happened during test execution.

Enabling Tracing in Your Tests

Basic Tracing Setup

To enable tracing in your Playwright tests, you need to configure it in your test setup:

// playwright.config.js
module.exports = {
  use: {
    // Enable tracing on retry attempts and first run
    trace: 'on-first-retry',
    // Alternative options:
    // trace: 'on', // Always record traces
    // trace: 'retain-on-failure', // Only keep traces for failed tests
    // trace: 'off', // Disable tracing
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
};

Programmatic Tracing

You can also control tracing programmatically within your tests:

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

test('example test with tracing', async ({ page, context }) => {
  // Start tracing before creating the page
  await context.tracing.start({ 
    screenshots: true, 
    snapshots: true, 
    sources: true 
  });

  try {
    await page.goto('https://example.com');
    await page.click('button#submit');
    await expect(page.locator('.result')).toBeVisible();
  } finally {
    // Stop tracing and save it to a file
    await context.tracing.stop({ path: 'trace.zip' });
  }
});

Python Tracing Configuration

For Python users, here's how to enable tracing:

# conftest.py
import pytest
from playwright.sync_api import sync_playwright

@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
    return {
        **browser_context_args,
        "trace": "on-first-retry"
    }

# test_example.py
import pytest
from playwright.sync_api import Page, expect

def test_with_tracing(page: Page, context):
    # Start tracing
    context.tracing.start(screenshots=True, snapshots=True, sources=True)

    try:
        page.goto("https://example.com")
        page.click("button#submit")
        expect(page.locator(".result")).to_be_visible()
    finally:
        # Stop tracing and save
        context.tracing.stop(path="trace.zip")

Tracing Configuration Options

Trace Recording Options

When starting tracing, you can configure what information to capture:

await context.tracing.start({
  screenshots: true,    // Capture screenshots on every action
  snapshots: true,      // Capture DOM snapshots
  sources: true,        // Include source code in traces
  title: 'My Test Trace' // Custom trace title
});

Global Tracing Settings

Configure tracing globally in your Playwright configuration:

// playwright.config.js
module.exports = {
  use: {
    trace: {
      mode: 'on-first-retry',
      snapshots: true,
      screenshots: true,
      sources: true
    }
  }
};

Viewing and Analyzing Traces

Opening the Trace Viewer

After your tests generate trace files, you can open them with the trace viewer:

# Open a specific trace file
npx playwright show-trace trace.zip

# Open the trace viewer with the last test run
npx playwright show-trace test-results/

# Python equivalent
playwright show-trace trace.zip

Trace Viewer Interface

The trace viewer provides several key sections:

  1. Timeline: Shows the sequence of actions and their timing
  2. Actions: Detailed list of each action performed
  3. Screenshots: Visual snapshots at each step
  4. Network: All network requests and responses
  5. Console: Console logs and errors
  6. Source: Source code context for each action

Analyzing Failed Tests

When debugging failed tests, focus on these areas:

// Example of a failing test that benefits from tracing
test('debug failed login', async ({ page }) => {
  await page.goto('https://example.com/login');

  // This might fail - trace will show why
  await page.fill('#username', 'testuser');
  await page.fill('#password', 'wrongpassword');
  await page.click('#login-button');

  // Assertion that might fail
  await expect(page.locator('.dashboard')).toBeVisible();
});

Advanced Tracing Techniques

Conditional Tracing

Enable tracing only for specific test conditions:

test('conditional tracing', async ({ page, context }) => {
  const shouldTrace = process.env.DEBUG === 'true';

  if (shouldTrace) {
    await context.tracing.start({ 
      screenshots: true, 
      snapshots: true 
    });
  }

  try {
    await page.goto('https://example.com');
    // Test logic here
  } finally {
    if (shouldTrace) {
      await context.tracing.stop({ path: 'debug-trace.zip' });
    }
  }
});

Multiple Trace Segments

Break down complex tests into multiple trace segments:

test('multi-segment tracing', async ({ page, context }) => {
  // First segment: Login
  await context.tracing.start({ title: 'Login Flow' });
  await page.goto('https://example.com/login');
  await page.fill('#username', 'user');
  await page.fill('#password', 'pass');
  await page.click('#login');
  await context.tracing.stop({ path: 'login-trace.zip' });

  // Second segment: Dashboard interaction
  await context.tracing.start({ title: 'Dashboard Flow' });
  await page.click('#dashboard-link');
  await expect(page.locator('.dashboard')).toBeVisible();
  await context.tracing.stop({ path: 'dashboard-trace.zip' });
});

Best Practices for Effective Debugging

1. Strategic Trace Placement

Place tracing around the most critical parts of your tests:

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

  // Start tracing before the critical section
  await context.tracing.start({ screenshots: true, snapshots: true });

  // Critical test logic that might fail
  await page.click('.complex-dropdown');
  await page.selectOption('select#options', 'value');
  await page.click('#submit');

  // Stop tracing after the critical section
  await context.tracing.stop({ path: 'critical-section.zip' });
});

2. Trace Organization

Organize traces with meaningful names and paths:

test('organized tracing', async ({ page, context }) => {
  const testName = 'user-registration';
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  const tracePath = `traces/${testName}-${timestamp}.zip`;

  await context.tracing.start({ title: testName });

  try {
    // Test logic
    await page.goto('https://example.com/register');
    await page.fill('#email', 'test@example.com');
    await page.click('#register');
  } finally {
    await context.tracing.stop({ path: tracePath });
  }
});

3. Combining with Other Debugging Tools

Use tracing alongside other debugging techniques for comprehensive analysis. Similar to how you might handle authentication flows in Puppeteer, Playwright's tracing can help you understand complex authentication scenarios step by step.

Troubleshooting Common Issues

Trace File Size Management

Large trace files can slow down analysis. Optimize by:

// Minimal tracing for performance
await context.tracing.start({
  screenshots: false,    // Disable screenshots if not needed
  snapshots: true,       // Keep snapshots for DOM analysis
  sources: false         // Disable source code if not debugging code
});

Network Request Analysis

Use traces to debug network-related issues:

test('network debugging', async ({ page, context }) => {
  await context.tracing.start({ 
    screenshots: true, 
    snapshots: true,
    sources: true
  });

  // Monitor network requests
  page.on('request', request => {
    console.log(`Request: ${request.url()}`);
  });

  page.on('response', response => {
    console.log(`Response: ${response.url()} - ${response.status()}`);
  });

  await page.goto('https://example.com');
  await context.tracing.stop({ path: 'network-trace.zip' });
});

Integration with CI/CD

Automatic Trace Collection

Configure automatic trace collection in CI environments:

# .github/workflows/tests.yml
name: Playwright Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright
      run: npx playwright install --with-deps
    - name: Run tests
      run: npx playwright test
    - name: Upload traces
      uses: actions/upload-artifact@v3
      if: failure()
      with:
        name: playwright-traces
        path: test-results/

Conclusion

Playwright's trace viewer is an essential tool for debugging failed tests effectively. By enabling tracing strategically, analyzing traces systematically, and combining tracing with other debugging techniques, you can quickly identify and resolve test failures. The visual timeline, detailed action logs, and network analysis capabilities make it much easier to understand what went wrong in your tests.

Remember to use tracing judiciously in production environments, as it can add overhead to test execution. Focus on enabling tracing for failed tests or specific debugging scenarios to maintain optimal test performance while gaining valuable debugging insights.

For more complex scenarios involving dynamic content, you might also want to explore how to handle AJAX requests effectively, as understanding asynchronous operations is crucial for successful web automation and testing.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon