Debugging Playwright Tests Like a Pro: A 2026 Guide
In the fast-paced world of web development, Playwright has emerged as the de facto standard for end-to-end testing. Its auto-waiting, multi-browser support, and powerful APIs make writing tests a joy. However, even the most well-crafted tests can fail. The true mark of an expert isn't just writing tests; it's knowing how to debug them efficiently when they break.
Gone are the days of relying solely on console.log statements and hoping for the best. Modern Playwright debugging is a rich, interactive experience. In this guide, we'll explore the professional toolkit for debugging Playwright tests in 2026, from local interactive debugging to unraveling the mysteries of CI failures.
1. The Interactive Power Trio: Inspector, UI Mode, and VS Code
When a test fails on your local machine, you need to see what the browser sees. Playwright offers three powerful, interactive ways to step through your code.
The Playwright Inspector: Your Step-by-Step Debugger
The Playwright Inspector is a GUI tool that allows you to step through each line of your test, inspect the DOM, and even try out alternative locators in real-time. To activate it, you set the PWDEBUG environment variable before running your test. This launches the browser in headed mode (so you can see it), disables timeouts, and opens the Inspector window .
# On macOS/Linux PWDEBUG=1 npx playwright test example.spec.ts # On Windows (PowerShell) $env:PWDEBUG=1 npx playwright test example.spec.ts
Once open, the Inspector window shows your code. You can use the "Step over" button to execute the code line by line, watching the browser update after each action. This is perfect for verifying that your locators are finding the right elements at the right time .
You can also force a pause at a specific point in your code without using the environment variable by adding await page.pause() directly into your script .
// example.spec.ts import { test, expect } from '@playwright/test'; test('should log in successfully', async ({ page }) => { await page.goto('https://example.com/login'); await page.fill('#username', 'testuser'); await page.pause(); // Execution will stop here and the Inspector will open await page.fill('#password', 'password123'); await page.click('button[type="submit"]'); await expect(page).toHaveURL(/.*dashboard/); });
UI Mode: The Visual Test Runner
For a more holistic view, Playwright's UI Mode (npx playwright test --ui) is a game-changer . It provides a dedicated graphical interface for running and debugging your entire test suite.
[Command to launch UI Mode]
npx playwright test --ui
In UI Mode, you get a live preview of your browser, a timeline of actions, and an action explorer that logs every click, type, and navigation . You can click on any action in the log to see a DOM snapshot of the page at that exact moment, revealing what the test "saw." This is invaluable for debugging flaky tests caused by timing issues or animations. You can also use the debug() method on a specific locator to pause the test right before an interaction .
// Pause right before interacting with a tricky element await page.locator('#submit-button').debug();
VS Code Integration: Debugging with Breakpoints
If you prefer staying in your Integrated Development Environment (IDE), Playwright's VS Code extension offers first-class debugging support. You can set breakpoints directly in your TypeScript/JavaScript code just like you would for any other Node.js application .
To set this up, create a launch configuration in your .vscode/launch.json file:
{ "version": "0.2.0", "configurations": [ { "name": "Debug Current Test", "type": "node", "request": "launch", "runtimeExecutable": "npx", "runtimeArgs": [ "playwright", "test", "${relativeFile}", "--headed" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] }
With this configuration, you can open a test file, hit F5, and the test will execute in headed mode, stopping at any breakpoints you've set, allowing you to inspect variables and the call stack .
2. Tracing and Logging: Solving the "It Worked Locally" Mystery
The most frustrating bugs are the ones that only happen in your Continuous Integration (CI) pipeline. You can't step through code in a CI environment, so you need a different strategy: forensic data collection.
Trace Viewer: A Time Machine for Your Tests
Playwright's Trace Viewer is the ultimate tool for post-mortem debugging. It records a full trace of your test, including screenshots at each action, console logs, network requests, and the complete DOM snapshot .
You can configure tracing in your playwright.config.ts file to capture traces only when a test fails, avoiding unnecessary overhead for passing tests .
// playwright.config.ts import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { // Capture trace on first retry of a failed test trace: 'on-first-retry', // Take screenshot on failure screenshot: 'only-on-fail', // Record video on failure video: 'retain-on-failure', }, });
After your CI run completes, you'll find trace.zip files in the test-results directory. View them with:
npx playwright show-trace path/to/trace.zip
This opens a GUI where you can scrub through your test, inspect the network activity, and see the exact state of the page when a locator failed .
Verbose Logging: Peeking Under the Hood
Sometimes you need to see what Playwright is doing internally. Enabling verbose API logs prints every internal Playwright action to the console, showing you locator resolution, timing, and retry attempts .
DEBUG=pw:api npx playwright test
This output can help you understand why a locator wasn't found—was it because the element was detached, or did Playwright simply time out waiting for it? For extremely low-level browser protocol debugging, you can use DEBUG=pw:browser*, but for most cases, pw:api is the sweet spot .
3. Network-Level Debugging: Intercepting and Inspecting Requests
Many UI failures stem from backend issues. Did the API return the wrong data? Is a request failing with a 500 error? Playwright allows you to inspect and even mock network traffic.
Waiting for and Asserting Responses
Instead of hard-coding a wait, you can wait for a specific network response to ensure the data your UI relies on has arrived .
test('should display the search results from API', async ({ page }) => { await page.goto('https://example.com/search'); // Click the search button await page.click('button#search'); // Wait for the API response we care about const response = await page.waitForResponse(async res => { return res.url().includes('/api/search') && res.status() === 200; }); // Optional: Inspect the response body const responseBody = await response.json(); console.log(responseBody); // Now assert that the UI updated correctly await expect(page.locator('.result')).toHaveCount(10); });
This technique makes your tests more robust and gives you a clear debugging point. If the assertion fails, you can check the captured response object to see exactly what the server sent back .
Leveraging Browser DevTools
Don't forget the classics. When running in debug mode (PWDEBUG=1), you can open your browser's native Developer Tools (F12) . The Playwright object is available in the console, allowing you to test and debug locators live .
// In the browser console when test is paused at page.pause() playwright.$('button:has-text("Submit")'); // Highlights the first matching element playwright.selector(document.querySelector('.error')); // Generates a unique selector for an element
You can also inspect the Network tab to see the exact sequence of requests, or the Console tab to check for JavaScript errors .
4. Pro Tips for Debugging the Toughest Bugs
When standard methods fail, it's time to bring out the heavy artillery.
Reproduce CI Conditions Locally
CI environments are often slower and more constrained than your powerful development machine. You can simulate these conditions locally to make "CI-only" failures reproducible .
# Run tests in headless mode (like CI) npx playwright test # Simulate a slower CPU (useful for catching race conditions) npx playwright test --workers=1 # Set CI environment variable (if your tests use it) CI=true npx playwright test
For ultimate fidelity, run your tests inside the same Docker container your CI uses. This eliminates environment drift caused by different operating system libraries or browser versions .
Isolate and Focus
When debugging a specific failure, don't run your entire 500-test suite. Use --grep or tags to focus on the problematic test .
// Tag a test test('checkout flow', { tag: '@checkout' }, async ({ page }) => { // ... test code });
# Run only tests with the @checkout tag npx playwright test --grep @checkout # Run a single test file npx playwright test tests/checkout.spec.ts
This shortens the feedback loop dramatically .
The AI-Powered Future: Playwright MCP
As we move through 2026, AI is becoming a powerful ally in debugging. The Playwright Model Context Protocol (MCP) server allows AI agents like GitHub Copilot to interact with your application . Imagine giving Copilot a bug report, and it uses Playwright MCP to automatically reproduce the steps, identify that an API call returned a 500 error, and then guide you to the backend code that caused it. This shifts your role from manually performing the repro steps to simply reviewing the AI's findings and the proposed fix .
Conclusion: From Detective to Master
Debugging is an inevitable part of testing, but it doesn't have to be a chore. By mastering these professional techniques, you can transform debugging from a frustrating game of guesswork into a structured investigation.
Use the Playwright Inspector, UI Mode, and VS Code for interactive, step-by-step debugging.
Rely on Traces and Logs to investigate failures in headless CI environments.
Intercept Network Requests to validate the connection between your frontend and backend.
Simulate CI conditions and isolate tests to tackle the most elusive bugs.
With this toolkit, you're not just fixing tests; you're building a deeper understanding of your application and ensuring its reliability with the precision of a true professional. Happy debugging