C.W.K.
Stream
Lesson 04 of 04 · published

UI Mode and the Trace Viewer

~16 min · playwright-setup, ui-mode, trace-viewer

Level 0Test Curious
0 XP0/32 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"The trace viewer is the single biggest reason to switch from Cypress."

UI Mode — the Local Test Dashboard

npx playwright test --ui opens a desktop-app-like dashboard inside a browser window. The left panel lists every test in your suite; click one to run it, watch it execute live in a small embedded browser, scrub through the timeline of actions, and inspect the DOM at any moment. It's the codification of the live debugging loop.

Features that earn the install:

  • Watch mode — UI mode auto-reruns tests when their source files change. Edit a spec, save, see the new run instantly.
  • Pick locator — hover any DOM element in the embedded preview, get the suggested Playwright selector.
  • Time-travel scrubbing — slide through the test's action timeline; the preview shows the DOM at that moment, the network panel shows requests in flight, the console shows logs.
  • Filter by status — show only failed / flaky / passed, filter by project or tag.

The Trace Viewer — the Forensic Tool

When a test fails, Playwright (if traces are enabled) records EVERYTHING: every action, before/after DOM snapshots, network requests, console messages, screenshots, test source lines, error stack trace. The package is a .zip in test-results/. Open it with npx playwright show-trace path/to/trace.zip — or drop it on trace.playwright.dev — and you get the same UI as Live mode, but for a past run.

The killer use case is CI failures. A test fails in CI, the terminal says "Locator expected to be visible, was hidden," and you can't reproduce it locally. Download the trace artifact from the CI run, open it, scrub to the failure, see the actual DOM at that exact moment — usually it tells you immediately what was different (a modal that didn't close, a timing issue, a different copy because of i18n).

Always enable traces on first retry. use: { trace: 'on-first-retry' } in your config is the default for a reason — zero overhead on success, full forensics on failure. The minor disk-space cost is nothing compared to the debugging hours it saves.

What the Trace Shows You

  • Action timeline — every click, fill, wait, with timing.
  • DOM snapshots — interactive (you can inspect, not just see) for each action, before and after.
  • Network panel — every request, method, status, response. Filter by failed.
  • Console panel — every console.log/warn/error from the page.
  • Source panel — your test code with the current line highlighted.
  • Errors — the failure with full stack trace.

Sharing Traces

The .zip is self-contained. Upload it as a CI artifact, attach to a bug report, send it to a teammate — they open it with the same tool and see exactly what you saw. No 'works on my machine' debate.

Screenshots and Video — Optional Lighter-Weight Records

Traces are heavy (multi-MB per failure). For lighter-weight failure records, enable screenshot: 'only-on-failure' and video: 'retain-on-failure' in use. These give you a final-state screenshot and a video of the run, respectively. Less detail than a trace, but smaller files and faster to glance at.

Code

UI mode + trace viewer commands·bash
# UI mode — the local dashboard
npx playwright test --ui

# Open a trace file you already have
npx playwright show-trace test-results/<test-name>/trace.zip

# Open a trace file from a downloaded CI artifact
npx playwright show-trace ~/Downloads/playwright-report/data/<hash>.zip
Trace config — defaults, always-on, manual·typescript
// Capture-on-first-retry — the default sweet spot
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    trace: 'on-first-retry',         // capture once on retry, never on success
    screenshot: 'only-on-failure',   // final-state screenshot on failure
    video: 'retain-on-failure',      // video of the failed run
  },
});

// Always-on tracing (for hard-to-reproduce flakes — disable after diagnosis)
export default defineConfig({
  use: {
    trace: 'on',                     // overhead, but every run has a trace
  },
});

// Per-test trace forcing (when you only need it for one diagnostic run)
import { test } from '@playwright/test';

test('flaky integration test', async ({ page }) => {
  await page.context().tracing.start({ screenshots: true, snapshots: true });
  // ... test body
  await page.context().tracing.stop({ path: 'manual-trace.zip' });
});
CI trace artifacts — upload + retrieve·yaml
# CI — upload trace artifacts so you can open them after a failure
- uses: actions/upload-artifact@v4
  if: ${{ !cancelled() }}
  with:
    name: playwright-report
    path: playwright-report/
    retention-days: 30

# Download from CI:
# 1. Open the failed run in Actions
# 2. Scroll to 'Artifacts' at the bottom
# 3. Download playwright-report.zip
# 4. Unzip, find trace.zip inside
# 5. npx playwright show-trace <path>
What the trace viewer layout looks like·text
Trace viewer panels — what each shows:

  ┌──────────────────────────────────────────────────────┐
  │ Timeline (top)                                       │
  │  ●──●──●──●──●──❌ ← scrub between actions          │
  │                                                      │
  │ ┌─────────────────────┐  ┌──────────────────────┐    │
  │ │ DOM Preview (left)   │  │ Source (right)        │    │
  │ │ Interactive snapshot │  │ Your test code        │    │
  │ │ at the selected time │  │ Current line highlight│    │
  │ └─────────────────────┘  └──────────────────────┘    │
  │                                                      │
  │ ┌─────────────────────────────────────────────────┐  │
  │ │ Tabs: Actions | Console | Network | Errors      │  │
  │ │                                                 │  │
  │ │ Network: GET /api/users 200 (124ms)             │  │
  │ │          POST /api/login 503 ← cause of failure │  │
  │ └─────────────────────────────────────────────────┘  │
  └──────────────────────────────────────────────────────┘

External links

Exercise

Run your test suite in UI mode (npx playwright test --ui). Click into the test list, run one test, watch it execute. Now deliberately break a test (wrong text in an assertion), run it again, and use the timeline scrubber to find the exact action where reality diverged from your expectation. Open the trace viewer separately on the .zip from test-results/ and confirm you get the same forensic view.
Hint
If UI mode shows 'No tests found,' your testDir setting probably doesn't match where your tests actually live. The terminal output of npx playwright test --list shows the resolved test paths — a quick sanity check.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.