Browser tests

Debug with traces

Use Playwright traces, screenshots, video, and reports to reconstruct a browser failure before adding retries.

When a browser test fails on CI, the page is gone. The process exited, the browser closed, and all you have is a log line. You need evidence that survives the run.

A Playwright trace is that evidence. It records every action, a DOM snapshot before and after each one, network requests, console output, and timing. You open it later and step through the test as if you were there.

Record traces when they matter

Recording a trace on every green run wastes time and disk. I configure it to record on the first retry, so normal runs stay cheap and a failure preserves the attempt that matters:

import { defineConfig } from '@playwright/test'

export default defineConfig({
  retries: process.env.CI ? 1 : 0,
  use: { trace: 'on-first-retry' }
})

When a test fails and gets retried, the retry runs with tracing on, and the trace lands in test-results/. Open it with:

npx playwright show-trace test-results/books-add-book-chromium-retry1/trace.zip

A retry is a clue, not a fix

If the first attempt fails and the retry passes, don’t move on. The run just told you the test is sensitive to timing, shared state, or the environment. Note it, look at the trace, and find the cause. A test that “passes on retry” is a flaky test with better PR.

Read the trace in order

Find the last action that succeeded. Then look at the next one: what did its locator resolve to, and which actionability check was failing? Compare the DOM snapshot before and after.

Then check the network panel for failed or slow requests, and the console for errors.

This separates three failures that look identical from the outside. “The button couldn’t be clicked” is a UI problem. “The click worked but the API returned 500” is a backend problem. “The API worked but the page never rendered the result” is a frontend rendering problem. Same red test, three different fixes.

Screenshots, video, and reports

A screenshot is one moment. It can’t show the 500, the redirect chain, or the element that got replaced between two steps. Video helps with motion and order. The HTML report groups failures and links their attachments.

Keep the smallest set of artifacts that answers the questions you’ll actually ask. And be careful publishing traces: they include the page content, so private test data and any secrets on screen go with them.

Try this: break a selector on purpose, run with tracing on, and open the trace. Find the last successful action and the DOM at the failure. Then make the API return 500 instead, and compare the network and console evidence. You should be able to explain why the two failures need different fixes.

Lesson completed