RizTech Academy logo
RizTech Academy
Web Automation with PlaywrightLesson 6 of 630 min

Traces, screenshots and debugging a failure

A test failed. Now what? A UI test failure that just says "expected visible, got hidden" is not much to go on — and if it failed in CI, on a machine you cannot see, it is worse. Playwright's answer is some of the best debugging in any test tool: it can record a trace of exactly what happened, take screenshots and video, and let you step through a test interactively. Knowing these turns a baffling failure into a five-minute fix. This lesson is debugging a failing Playwright test.

First, read the failure

Before any tool, read what Playwright already tells you. A failure prints the assertion that failed, the locator involved, the expected and actual, and a snippet of the page. Often that is enough: getByRole('button', { name: 'Sign in' }) "resolved to 0 elements" means the button was not found — a wrong name, or the page did not load. expect(...).toHaveCount(11) "received 1" means only the header row was present — the data did not load. Read the message and the line before reaching for heavier tools; half the time it names the problem.

Traces: a recording of the whole test

A trace is Playwright's most powerful feature. It records, for every step, a snapshot of the DOM, the action taken, the network requests, the console, and screenshots — a complete timeline you can scrub through after the fact. Turn it on in the config:

use: { trace: 'on-first-retry' }   // AgentPay: record a trace when a test retries

'on-first-retry' (what AgentPay uses) records only when a test fails and retries — cheap, and you get a trace exactly when you need one. Then open it:

npx playwright show-trace trace.zip

The trace viewer shows the timeline, and for each step a before/after snapshot of the page you can inspect — hover the failing step and see exactly what the page looked like, what was on it, what the network was doing. For a CI failure you cannot reproduce locally, the trace is often the only way to see what happened — download it from the CI artifacts (the CI module wires this up) and scrub through. Traces are the single biggest reason a Playwright failure is diagnosable.

Screenshots and video

Simpler artifacts, useful at a glance:

  • Screenshot on failure — use: { screenshot: 'only-on-failure' } (AgentPay sets this) captures the page at the moment of failure. A picture instantly shows "the page is on the login screen, not the dashboard" or "an error banner is showing".
  • Video — use: { video: 'retain-on-failure' } records the whole test; watch the run to see where it went wrong. Heavier than a trace but sometimes clearer for a timing issue.

These are automatic once configured, and they attach to the HTML report (below), so a CI failure comes with a picture without any extra work.

Debugging interactively

When you can run locally, step through the test:

  • UI mode — npx playwright test --ui opens a visual runner: pick a test, watch it run step by step, see the DOM snapshot at each step, and time-travel. The best way to develop and debug tests.
  • Debug mode / Inspector — npx playwright test --debug runs headed and pauses so you can step through, and opens the Inspector where you can try locators live against the real page (invaluable when a locator is not matching).
  • Headed — --headed simply shows the browser so you watch it happen.
  • page.pause() — drop it into a test to pause execution there and open the Inspector at that point.

Developing a new test in UI mode, and reaching for --debug when a locator will not match, is the normal workflow — far faster than adding console.logs.

The HTML report

Playwright generates an HTML report of a run — every test, its status, and for failures the error, the screenshot, and the trace, all in one page:

npx playwright show-report

AgentPay's config produces this report in CI (reporter: [['github'], ['html', …]]) and uploads it as an artifact, so when the CI module runs the suite on every change, a failure comes with a browsable report: click the failed test, see the screenshot, open the trace. That is what makes a CI failure actionable rather than a dead end — which, as the whole automation part insisted, is the difference between a suite people act on and one they ignore.

A debugging routine

Put it together into a routine for any failing test:

  1. Read the error — the assertion, locator, expected vs actual. Often enough.
  2. Look at the screenshot — what state was the page actually in?
  3. Open the trace — scrub to the failing step, inspect the DOM snapshot and network at that moment.
  4. Reproduce in UI/debug mode locally — step through, try the locator live in the Inspector.
  5. Fix the cause — a wrong locator, a missing wait (add a web-first assertion, never a sleep), or a real bug in the app (the best outcome — the test did its job).

Most failures fall out at step 1 or 3. And note the distinction that matters: sometimes the test is wrong (fix the test), and sometimes the app is wrong (you found a bug — file it, per the bug-reports lesson). A good debugging habit is what lets you tell the two apart quickly.

Check your work

Read the failure first — Playwright names the failed assertion, the locator, expected vs actual, and a page snippet; "resolved to 0 elements" = not found, "received 1" for a row count = data did not load. Half of failures are solved here.

Traces (trace: 'on-first-retry') record a full timeline — DOM snapshots, actions, network, console — scrubbable in show-trace. Often the only way to diagnose a CI-only failure (download from artifacts). The biggest reason Playwright failures are diagnosable.

Screenshots (screenshot: 'only-on-failure') and video (retain-on-failure) capture the failure state automatically and attach to the report.

Interactive: UI mode (--ui, step through + time-travel — best for developing), debug mode (--debug, pause + live-try locators in the Inspector), --headed, and page.pause().

HTML report (show-report) collects every test with errors, screenshots and traces; AgentPay uploads it in CI so a failure is browsable and actionable.

Routine: read error → screenshot → trace → reproduce in UI/debug → fix (wrong locator, missing wait, or a real app bug — tell test-wrong from app-wrong).

Practice

  1. Make an AgentPay test fail (wrong button name) and read the error; identify the cause from the message alone.
  2. Enable traces, cause a failure, and open the trace with show-trace; scrub to the failing step and inspect the DOM snapshot.
  3. Turn on screenshot: 'only-on-failure' and confirm the failure screenshot shows the page state.
  4. Run the suite in --ui mode and step through a test; then use --debug to try a locator live in the Inspector.
  5. Generate and open the HTML report; find a failed test's screenshot and trace in it.
  6. Take one failure and decide whether the test or the app is wrong, and justify which fix is correct.

Official documentation

Next: the api-automation module — automating the API tests you designed by hand.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship