vi.defineHelper() example for trace markers
```ts
import { vi } from 'vitest'
import { page } from 'vitest/browser'
const myRender = vi.defineHelper(async (content: string) => {
document.body.innerHTML = content
await page.elementLocator(document.body).mark('render helper')
})
test('renders content', async () => {
await myRender('<button>Hello</button>') // trace points to this line
})
```
View Playwright trace files
To open a trace file, run `npx playwright show-trace "path-to-trace-file"` in the terminal to start the Trace Viewer. Alternatively, open https://trace.playwright.dev in a browser and upload the trace file there.
Automatic source location mapping in traces
Vitest automatically groups browser interactions and links them back to the exact line in your test that triggered them. This happens for expect.element() assertions, interactive actions (click, fill, type, hover, selectOptions, upload, dragAndDrop, tab, keyboard, wheel), and screenshots.
Traces available in test reporters as annotations
Trace files are available in reporters as annotations. For example, in the HTML reporter, you can find the link to the trace file in the test details.
Enable Playwright traces in browser mode config
To enable Playwright trace file generation in Vitest Browser Mode, set the `trace` option in the `test.browser` configuration. Trace files can only be generated when using the Playwright provider. Basic configuration sets `trace: 'on'` to generate a trace file for each test.
Trace generation CLI command
To enable Playwright traces via CLI, use the command `vitest --browser.trace=on`.
Trace file generation modes
The `trace` option accepts the following values: 'on' generates a trace file for each test, 'on-first-retry' generates traces only on the first retry, 'on-all-retries' generates traces on all retries, and 'retain-on-failure' generates traces only when tests fail.
Trace file naming convention
Trace files are automatically named with the pattern: `projectName-testName-repeatCount-retryCount.trace.zip`. For example, `chromium-my-test-0-0.trace.zip` indicates the chromium project, 'my-test' test name, 0 repeat count, and 0 retry count.
Default trace file output location
By default, trace files are saved in a `__traces__` folder located next to your test files.
Configure custom trace output directory
To change the trace file output directory, set the `tracesDir` option in the `test.browser.trace` configuration object. The path is relative to the root of the project. This stores all traces in a single directory grouped by test file.
Custom trace output directory configuration example
```ts
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
provider: playwright(),
trace: {
mode: 'on',
tracesDir: './playwright-traces',
},
},
},
})
```
Trace markers with page.mark()
Add explicit named markers to the trace timeline using `page.mark(name)` on a page or locator object. For example, `await page.getByRole('button', { name: 'Sign in' }).mark('sign in button rendered')` adds a marker to the trace.
Group trace markers with callback
Use `page.mark(name, callback)` to group multiple operations under one trace marker. The callback wraps multiple operations like fill, click, and other actions into a single named trace group.
Trace marker grouping example
```ts
await page.mark('sign in flow', async () => {
await page.getByRole('textbox', { name: 'Email' }).fill('john@example.com')
await page.getByRole('textbox', { name: 'Password' }).fill('secret')
await page.getByRole('button', { name: 'Sign in' }).click()
})
```
vi.defineHelper() for reusable trace-aware helpers
Wrap reusable helper functions with `vi.defineHelper()` so that trace entries point to the line where the helper is called, not to the internals of the helper function.
browser.traceView.inlineImages option
The inlineImages option stores loaded <img> pixels in the trace snapshot. This is mostly useful for the HTML reporter to make the report portable without depending on external image URLs. This is pixel capture, not original resource capture: SVGs are rasterized, animated images are not preserved as animations, and CSS background images or fonts are not covered. Cross-origin images need CORS-readable pixels to be inlined.
browser.traceView.recordCanvas option
The recordCanvas option stores readable canvas pixels in the trace snapshot. This is useful for charts and simple 2D canvas output, but it is not a full canvas drawing timeline and does not provide complete WebGL replay. Enabling recordCanvas allows scripts inside the replay iframe for security.
Configure traceView with object form
The traceView option can use an object form to enable additional fidelity options: { enabled: true, inlineImages: true, recordCanvas: true }
External resource limitations in trace view
Trace view does not provide a general resource store. CSS background images and @font-face files referenced from serialized CSS remain URL-backed and depend on their original URLs. External images can render in the viewer when the browser can load the URL, but they are not portable in the HTML reporter unless inlineImages can capture their pixels. Cross-origin images need CORS-readable pixels for portable capture.
browser.traceView vs browser.trace comparison
browser.traceView and browser.trace are independent features. browser.traceView supports all providers (playwright, webdriverio, preview) and uses rrweb DOM snapshots viewable in Browser UI, Vitest UI, or HTML reporter without external tools. browser.trace is Playwright-only and uses Playwright .trace.zip format viewable in Playwright Trace Viewer, requiring external tool (npx playwright show-trace). Both can be enabled simultaneously.
Common setups for browser.traceView
browser.traceView works with different configurations: 'vitest --browser.traceView' uses default local headed browser UI with trace replay; 'vitest --browser.traceView --browser.headless --ui' runs headless browser with Vitest UI showing traces; 'vitest --browser.traceView --browser.headless=false --browser.ui=false --ui' shows traces in Vitest UI while tests run in separate headed browser; 'vitest run --browser.traceView --reporter=html' generates static HTML report with trace viewer.
Trace viewer in Vitest UI streams entries during test
In Vitest UI, trace entries are streamed as the test runs, so you can inspect recorded steps before the test finishes. Long-running actions, expect.element(...) assertions, and callback page.mark() entries appear as in-progress steps first, then update with their final status and duration.
browser.traceView feature overview
browser.traceView records browser interactions as DOM snapshots and lets you replay them step by step in Vitest's built-in trace viewer. It is useful for inspecting earlier tests, failed retries, screenshots, assertions, and user actions after the browser has moved on. Trace view is additive and does not force a single debugging mode—you can use it with the normal local browser UI, with a headless browser and Vitest UI, or with the HTML reporter in CI.
Enable browser.traceView in vitest.config.ts
To enable trace view, set the browser.traceView option to true in the vitest.config.ts file under test.browser configuration.
Enable browser.traceView via CLI
Trace view can be enabled from the command line using the flag: vitest --browser.traceView
Trace viewer panes
The trace viewer has two resizable panes: the Step list (left) showing every recorded action, assertion, mark, and lifecycle entry with name, timing, selector, and source location—with failed actions and assertions highlighted in red; and the DOM snapshot (right) showing a reconstruction of the page at the selected step with the interacted element highlighted in blue.
Automatically recorded trace entries
Trace entries are recorded automatically for: expect.element(...) assertions; interactive actions like click, dblClick, tripleClick, fill, clear, type, hover, selectOptions, upload, dragAndDrop, tab, keyboard, wheel, and screenshots; and test runner lifecycle events (e.g. vitest:onAfterRetryTask is recorded after each test and retry run). Each entry captures the DOM state, timing information, the selector, and the source location.
page.mark() custom trace entries
You can insert custom named trace entries with page.mark(). It can be called without arguments to mark a point: await page.mark('content rendered'). It can also be called with a callback to group actions, though grouping is not fully supported and each inner action is recorded individually with the mark entry appearing at the end: await page.mark('sign in flow', async () => { ... }).
locator.mark() custom trace entries
Locators can also have custom trace entries added with locator.mark(): await page.getByRole('button', { name: 'Sign in' }).mark('sign in button')
vi.defineHelper() for trace entries in helpers
Use vi.defineHelper() to make trace entries from reusable helper functions point to the call site rather than the helper's internals. This ensures trace entries are attributed to the correct location in the test code.
Trace view handling of retries and repeats
Each attempt—retry or repeat—is recorded as a separate trace. When a test has multiple attempts, the viewer opens the most recent one by default. You can switch between attempts in the Report tab.
Default snapshot fidelity in trace view
By default, trace view captures the DOM tree, attributes, form values, same-origin readable CSS, element scroll positions, viewport size, and window scroll position. Images and canvas pixels are not inlined by default.
CSS capture in trace view snapshots
Stylesheets are captured through the browser's CSSOM. Readable <style> tags and same-origin <link rel="stylesheet"> files are serialized into the snapshot and replayed as inline styles. This captures the parsed CSS rules the browser applied, not the exact original stylesheet bytes; comments, formatting, invalid rules, and CSS resource files like background images or fonts are not bundled this way.