Capture fixtures
The reporter uploads complete test results — statuses, errors, traces, HTML reports — without any change to your test code. The capture fixtures are an optional, one-file addition that observes your tests from the inside and unlocks the dashboard's richest features: slow-endpoint analysis, Web Vitals, console capture, failure-time ARIA snapshots, and locator healing.
If you do one thing beyond installing the reporter, do this.
Setup
Option A — extend your existing fixtures:
// tests/fixtures.ts
import { test as base, expect } from '@playwright/test'
import { piwiFixtures } from '@piwitests/reporter'
export const test = base.extend(piwiFixtures)
export { expect }Option B — one-line extend with extendPiwiFixtures:
// tests/fixtures.ts
import { test as base } from '@playwright/test'
import { extendPiwiFixtures } from '@piwitests/reporter'
export const test = extendPiwiFixtures(base)
export { expect } from '@playwright/test'Then import test from your fixtures file in every spec. A spec that imports test from @playwright/test directly still runs and reports fine — it just isn't captured:
import { test, expect } from './fixtures'
test('homepage loads', async ({ page }) => {
await page.goto('/')
// network, console, Web Vitals, and locator data are captured automatically
})That's the entire setup — there is nothing to start, wrap, or await inside your tests.
What gets captured
| Data | Captured | Powers |
|---|---|---|
| Network requests — method, URL, status, duration, content type. Only API/document traffic (fetch, XHR, document); static assets are skipped | per request | Slow API endpoints table on the run page with /api/users/:id-style route normalization; backend log correlation via the X-Piwi-Logs response header |
Console entries — warning, error, and assert messages with source location (console.log noise is not collected) | as they happen | Console card on the test case page; AI diagnosis evidence |
| Web Vitals — TTFB, DOM Interactive, DOMContentLoaded, Load Complete, First Paint, First Contentful Paint, plus LCP, CLS and INP (Chromium-only) | at test teardown | Web vitals card with color-coded thresholds; performance trends |
| ARIA snapshot of the final page state | on failure | Failure evidence on the test-case and cluster pages; AI diagnosis context |
| Locator snapshots — element attributes, stable-ancestor anchors, and same-role position, plus ranked alternative locators (including rename-proof ancestor-scoped and name-free ones) for each acted-on element, stamped with the call site | after each successful action | Locator healing; when a failing name-based locator (getByRole, getByText, getByLabel, …) matches nothing, a fresh suggestion is attached to the test as a Playwright annotation |
With and without the fixtures
The reporter degrades gracefully — nothing breaks without the fixtures. This is exactly what you give up:
| Dashboard feature | Reporter only | Reporter + fixtures |
|---|---|---|
| Run history, statuses, errors, traces, HTML reports | ✅ | ✅ |
| Live streaming, sharding, CI/SCM metadata | ✅ | ✅ |
| Failure clustering & flaky-test analytics | ✅ | ✅ |
| AI failure diagnosis | ✅ error + code-diff grounding | ✅ richer evidence: ARIA snapshot, console, network |
| Slow API endpoints table | — | ✅ |
| Web Vitals & performance trends | — | ✅ |
| Console warnings/errors card | — | ✅ |
| Failure-time ARIA snapshot + locator suggestion | — | ✅ |
| Locator healing (ranked alternatives panel) | — | ✅ |
| Backend log correlation | — | ✅ with a backend integration |
Where capture works
The fixtures wire capture at the browser level, so it works however your tests create pages:
- the standard
pagefixture, browser.newPage()andbrowser.newContext().newPage()— including inside your own custom fixtures,- popups (
window.open) and pages a context opens on its own.
Semantics worth knowing:
beforeAll/afterAllactivity is intentionally not captured — only what happens inside a test is attributed to that test.- Multi-page tests attribute Web Vitals and the failure ARIA snapshot to the most recently active page.
- Repeated call sites (actions in loops) keep the latest capture per call site — the dashboard stores one locator snapshot per location.
Composing with your own fixtures
piwiFixtures is a plain Playwright fixtures object, so it composes with your own fixtures in any order:
import { test as base, mergeTests } from '@playwright/test'
import { piwiFixtures, extendPiwiFixtures } from '@piwitests/reporter'
// Your fixtures first, capture second
export const test = base.extend<MyFixtures>({ /* ... */ }).extend(piwiFixtures)
// Capture first, your fixtures second
export const test = extendPiwiFixtures(base).extend<MyFixtures>({ /* ... */ })
// Or merge two independent test objects
export const test = mergeTests(myTest, extendPiwiFixtures(base))Two rules:
- The fixture name
piwiCaptureis reserved — defining your own fixture with that name replaces the capture teardown and silently disables the attachments.piwiFixturestypes it, so a redefinition with an incompatible type is a compile error; a same-typed (void) one still compiles, so avoid the name entirely. - If you override
browserorpageyourself, extend withpiwiFixturesafter your override so the capture wrapping still applies.
Cost & opt-outs
Capture is designed to never fail or noticeably slow down a test:
- Per action: one DOM read, and occasionally a bounded ARIA snapshot (500 ms deadline).
- At teardown: draining in-flight captures is capped at 2 seconds.
- A capture that can't complete (mid-navigation, detached element) is dropped silently — it never throws into your test.
| Option | Effect |
|---|---|
collectPerformanceMetrics: false | Master switch — disables all fixture capture |
captureLocators: false (or PIWI_CAPTURE_LOCATORS=false) | Disables only the per-action locator snapshots; network, console, and Web Vitals stay on |
capturePageState: false (or PIWI_CAPTURE_PAGE_STATE=false) | Disables only the test-end app-state capture (URL, storage key names, cookie flags — values are never captured) |
Troubleshooting
- Data missing for some specs only — those specs import
testfrom@playwright/testinstead of your fixtures file. Capture is per-test-object; the import is the switch. - No fixture data at all — check that
collectPerformanceMetricsis notfalse, and that tests navigate to a real page (about:blank-only tests produce no Web Vitals). - ARIA snapshot or locator healing missing — same root causes as above; also check
captureLocators/PIWI_CAPTURE_LOCATORS.
Try it
A runnable example project exercising every capture path — including an intentionally failing test that lights up the ARIA snapshot, the locator suggestion, and the healing panel — lives in examples/playwright-fixtures.