Debugging and Tracing

By Syncfusion®, Inc. · Last updated

Reading Playwright error messages, call logs and code frames, the Playwright Inspector with --debug and page.pause(), headed runs and slow motion, UI Mode, the VS Code extension, logging with console.log, test.step and attachments, listening to page console messages and errors, recording and reading traces in the Trace Viewer, screenshots and videos on failure, and a checklist for flaky tests.

Debugging and Tracing

  • Every test fails sometimes. What matters is how fast you find out why.
  • Playwright gives you clear error messages, tools to pause and step through a test, and traces that record everything that happened.
  • In this lesson, you will read errors, try the debugging tools and use the lab's Trace Viewer.

Simple lesson: read the error first. If it is not enough, look at the trace.

A Real-World Example

  • A teammate's test passed yesterday. Today it fails. The cart button now appears on every product card.
  • Run it and read the output from top to bottom. The answer is already there.
  • The error says strict mode violation: the locator found several buttons. Playwright even suggests better locators. Locators explains the fix.

What You Will Learn

  1. How to read an error message, call log and code frame.
  2. The debugging tools: Inspector, page.pause(), headed mode, UI Mode and VS Code.
  3. Logging with console.log, test.step() and attachments.
  4. Catching the page's own console messages and errors.
  5. Recording and reading traces.
  6. Screenshots and videos on failure, and a flaky test checklist.

Reading Failures

The Parts of an Error

  • The error line: what failed, like locator.click: Timeout 5000ms exceeded or expect(locator).toHaveText(expected) failed.
  • Expected and Received: for assertions, what you wanted and what the page had.
  • The call log: what Playwright tried, step by step. "waiting for element to be visible", "element is not enabled", "intercepts pointer events".
  • The code frame: the exact line in your test, with a > and a ^ under the call.

Animation: an error report is highlighted part by part: first the error line, then expected and received values, then the call log, then the code frame with the failing line

Error: expect(locator).toHaveText(expected) failed

Expected: "2 products" Received: "1 product"

- waiting for getByRole('status').first() - unexpected value "1 product"

5 | await page.getByLabel('Category').selectOption('Shoes'); > 6 | await expect(page.getByRole('status')...).toHaveText('2 products'); | ^

Error line, expected and received, call log, code frame. Read them in this order.

Timeouts Tell a Story

  • locator.click: Timeout 5000ms exceeded means Playwright never found a clickable element. The call log says why: not found, hidden, disabled or covered.
  • Test timeout of 30000ms exceeded means the whole test ran too long. Look at the last step that started.
  • An assertion timeout means the page never reached the expected state. Compare Expected and Received.

Simple lesson: the call log is the most useful part. It says what Playwright waited for.

Debugging Tools

The Playwright Inspector

  • npx playwright test --debug runs headed, with one worker, and opens the Playwright Inspector.
  • The Inspector pauses before each action. You can step over actions, see the locator highlighted on the page, and try new locators in Pick locator.
  • npx playwright test example.spec.ts:10 --debug debugs only the test on line 10.

page.pause()

  • Put await page.pause() in a test to stop there and open the Inspector.
  • It only pauses in headed runs. In headless runs it does nothing, so a forgotten one does not block CI. Still, remove it when you are done.
test('checkout', async ({ page }) => {
  await page.goto('/cart');
  await page.pause(); // look around, then press Resume
  await page.getByRole('button', { name: 'Checkout' }).click();
});

Headed Mode and Slow Motion

  • --headed shows the browser window. Tests run at full speed, so it can be hard to follow.
  • Slow motion adds a pause after each action. Set it in the config while you debug:
use: {
  launchOptions: { slowMo: 500 }, // 0.5 seconds after every action
},

UI Mode

  • npx playwright test --ui opens UI Mode: a window that lists your tests, runs them, and shows a trace of every run.
  • Watch mode (the eye icon) re-runs a test whenever you save its file.
  • You can step through actions in a timeline, see the page before and after each one, and pick locators.
  • Many people keep UI Mode open while they write tests.

The VS Code Extension

  • The Playwright Test for VS Code extension adds a green ▶ next to each test.
  • Right-click the ▶ to Debug Test. Set breakpoints like in any code. The browser pauses with your code.
  • It can Pick locator, Record new tests (Codegen) and Show browser while tests run.

The lab cannot open real browser windows, so --debug, --ui and page.pause() print a note and carry on. The lab's Steps and Trace tabs show what those tools would show you.

Simple lesson: --debug steps through a test. --ui is the all-in-one view. VS Code adds breakpoints.

Logging What Happens

console.log, test.step and Attachments

  • console.log() in a test prints to the terminal. Use it to see values, like a product count.
  • test.step('name', async () => { ... }) groups actions. Steps show in the report, the trace and the lab's Steps tab, so you know which part failed.
  • testInfo.attach() saves extra data with the result, such as the HTML of the page or a JSON response.
  • Open the Steps tab. Each step groups its actions, and the attachment is listed under the test.

The Page's Own Console and Errors

  • The page can log messages and throw errors too. They often explain a broken page.
  • page.on('console', msg => ...) hears every console.log, console.warn and console.error from the page.
  • page.on('pageerror', error => ...) hears uncaught exceptions.
  • A common pattern: collect error messages and fail the test if any appear.

Simple lesson: steps and logs tell the story of a test. The page's console tells the story of the page.

Traces

What a Trace Records

  • A trace is a recording of one test run, saved as trace.zip.
  • It holds every action and assertion, a DOM snapshot of the page before and after each one, network calls, console messages, errors and the test source.
  • The Trace Viewer opens it: npx playwright show-trace path/to/trace.zip, or drop the file on trace.playwright.dev. The file never leaves your computer.

Turning Tracing On

  • In the config: use: { trace: 'on-first-retry' }. This is the default in new projects. A trace is recorded only when a test is retried, so passing runs stay fast.
  • Other modes: 'on' (always), 'retain-on-failure' (record always, keep only failures), 'off'.
  • On the command line: npx playwright test --trace on.
  • Open the Trace tab. Click each action on the left. The page snapshot shows the page at that moment, with the target outlined in red.
  • Check the Network list. The call for ?category=Shoes returned one product. The page was right. The test expected the wrong number.
  • The terminal shows the show-trace command. In the lab, typing npx playwright show-trace in the command bar opens the Trace tab.

On CI, upload the test-results folder as an artifact. When a test fails there, download its trace.zip and open it on your computer. CI/CD and Scaling shows the workflow step.

Traces for Flaky Tests

  • A flaky test fails, then passes on retry. With trace: 'on-first-retry', the retry is recorded.
  • The Sync practice page fails on the first click, like a real flaky page. Run this box and open the Trace tab.
  • The run is marked flaky. The Trace tab offers the retry's trace. Compare it with what you would expect from the first try.

Screenshots and Videos on Failure

  • screenshot: 'only-on-failure' saves a screenshot when a test fails.
  • video: 'retain-on-failure' records a video of each test and keeps it only when the test fails.
  • Both appear in the HTML report next to the trace. Traces are usually more useful, because you can inspect the page.
  • Video options include size, fps and show.actions, which draws the cursor and highlights each action in the recording.
use: {
  trace: 'on-first-retry',
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
},

Simple lesson: a trace is a full recording. Turn it on for retries and failures.

Fixing Flaky Tests

A Checklist

  • A missing await: the next line runs before the action finished. TypeScript and the @typescript-eslint/no-floating-promises rule catch most of these.
  • Fixed waits: waitForTimeout(1000) is too short on a slow day. Use web-first assertions.
  • Racing the network: the test checks before the data arrives. Wait for the response or for the result on the page.
  • Shared data: two parallel tests change the same account or cart. Give each test its own data.
  • Order dependence: a test only passes after another one. Each test must set up what it needs.
  • npx playwright test --repeat-each=10 runs each test ten times. A flaky test usually shows itself.

Retries hide flakiness, they do not fix it. Treat a flaky test as a bug: find the cause in its trace, then fix the test or the app.

Simple lesson: flaky tests have causes. Traces and --repeat-each help you find them.

Try It in Your Project

  • These steps take the lesson from the lab to your own app.
  • Set trace: 'on-first-retry' and upload test-results on CI.
  • Next time a test fails on CI, open its trace before changing any code.
  • Install the VS Code extension and debug one test with a breakpoint.

Simple lesson: use one idea from this lesson on your own app this week.

TL;DR

  • Read the error line, expected and received, the call log and the code frame.
  • --debug and page.pause() open the Inspector. --ui opens UI Mode. VS Code adds breakpoints.
  • test.step(), console.log() and attach() explain a test. page.on('console') hears the page.
  • Traces record actions, DOM snapshots, network and console. Use trace: 'on-first-retry'.
  • show-trace or trace.playwright.dev opens them. Upload them from CI.
  • Flaky tests have causes: missing await, fixed waits, network races, shared data.

Common mistakes

MistakeWhat happensFix
Reading only the first line of the errorYou miss what Playwright waited forRead the call log and code frame
Adding waitForTimeout() to fix a failureSlower tests that still fail sometimesFind the real cause, then use web-first assertions
trace: 'on' for every run on CIBig artifacts and slower runs'on-first-retry' or 'retain-on-failure'
Leaving page.pause() in a testHeaded runs stop and waitRemove it after debugging
Raising retries to hide flaky testsReal bugs shipUse the trace to fix the cause

Check Yourself

Exercises

What to Remember

  • Read the error, the call log and the code frame, in that order.
  • --debug, page.pause(), --ui and VS Code let you watch and step.
  • test.step() and the page console explain what happened.
  • Traces record everything. trace: 'on-first-retry' is a good default.
  • Flaky tests have causes. Find them, do not hide them with retries.

Next: Reporting