Clear and concise description of the problem
Draft brainstorm with Claude
As a developer using Vitest browser mode, I want a built-in trace viewer — like Playwright's — that lets me step through my test and inspect the DOM at each action, directly in Vitest UI and the HTML reporter.
Currently, browser mode has a mark API and trace support, but it fully delegates to Playwright's trace system:
- Produces
.trace.zip files that must be opened in Playwright's separate trace viewer
- Playwright-provider-only — gated behind
if (provider.name === 'playwright'), so WebDriverIO and preview users get nothing
- No integration with Vitest UI or HTML reporter — trace data exists but Vitest doesn't render it
The goal is for Vitest to have its own trace viewer with DOM snapshot support — provider-agnostic and built into the UI/reporter. Playwright trace output can remain as an optional secondary output.
Suggested solution
Build a built-in trace viewer by porting Playwright's DOM snapshot serialization and rendering into Vitest. The system captures a DOM snapshot at each mark point and renders it in Vitest's own UI.
What to port from Playwright (Apache 2.0, compatible with attribution):
- DOM serializer (
snapshotterInjected.ts, ~650 lines) — injected into the browser page. Serializes the DOM into a compact array-based format capturing form state, scroll positions, shadow DOM, adopted stylesheets, and more.
- Snapshot renderer (
snapshotRenderer.ts, ~300 lines) — converts the compact format back into viewable HTML, restoring all captured state.
- Type definitions (
snapshot.ts) — NodeSnapshot, FrameSnapshot, ResourceOverride.
Integration with existing infrastructure:
- Client side: At each
mark() / expect.element() / locator action, run the DOM serializer and send snapshot data via the existing WebSocket RPC alongside the mark payload.
_markTrace handler: Remove the provider gate. Capture DOM snapshots for all providers. Optionally still delegate to Playwright trace.
- Server: Add HTTP endpoints to serve rendered snapshots via the existing Vite dev server (e.g.,
/snapshot?id=... serving HTML in an iframe).
- Trace viewer UI: New component in Vitest UI and HTML reporter — a timeline of marks with an inline DOM snapshot preview for the selected step, similar to Playwright's trace viewer.
What can be deferred:
- Network HAR recording
- Canvas content population
- Cross-snapshot subtree deduplication
- Video/screencast
Alternative
- Embed Playwright's trace viewer directly. Downside: remains Playwright-only, heavy dependency, and doesn't integrate with Vitest's UI.
- Use simple
outerHTML instead of the compact format. Downside: misses form state, scroll positions, shadow DOM; much larger output; no deduplication.
Additional context
The DOM serializer runs as injected JS in the browser page (not through any provider API), making it naturally provider-agnostic. WebDriverIO and preview providers get DOM snapshot support for free.
The mark API already fires at all the right moments — this is about capturing DOM state at those existing hook points and rendering it in Vitest's own viewer:
page.mark(name) — explicit marks
locator.mark(name) — marks with element selector
expect.element() settlement — automatic marks after DOM assertions
runner.onAfterRetryTask — marks on test retry
Validations
Clear and concise description of the problem
Draft brainstorm with Claude
As a developer using Vitest browser mode, I want a built-in trace viewer — like Playwright's — that lets me step through my test and inspect the DOM at each action, directly in Vitest UI and the HTML reporter.
Currently, browser mode has a
markAPI and trace support, but it fully delegates to Playwright's trace system:.trace.zipfiles that must be opened in Playwright's separate trace viewerif (provider.name === 'playwright'), so WebDriverIO and preview users get nothingThe goal is for Vitest to have its own trace viewer with DOM snapshot support — provider-agnostic and built into the UI/reporter. Playwright trace output can remain as an optional secondary output.
Suggested solution
Build a built-in trace viewer by porting Playwright's DOM snapshot serialization and rendering into Vitest. The system captures a DOM snapshot at each
markpoint and renders it in Vitest's own UI.What to port from Playwright (Apache 2.0, compatible with attribution):
snapshotterInjected.ts, ~650 lines) — injected into the browser page. Serializes the DOM into a compact array-based format capturing form state, scroll positions, shadow DOM, adopted stylesheets, and more.snapshotRenderer.ts, ~300 lines) — converts the compact format back into viewable HTML, restoring all captured state.snapshot.ts) —NodeSnapshot,FrameSnapshot,ResourceOverride.Integration with existing infrastructure:
mark()/expect.element()/ locator action, run the DOM serializer and send snapshot data via the existing WebSocket RPC alongside the mark payload._markTracehandler: Remove the provider gate. Capture DOM snapshots for all providers. Optionally still delegate to Playwright trace./snapshot?id=...serving HTML in an iframe).What can be deferred:
Alternative
outerHTMLinstead of the compact format. Downside: misses form state, scroll positions, shadow DOM; much larger output; no deduplication.Additional context
The DOM serializer runs as injected JS in the browser page (not through any provider API), making it naturally provider-agnostic. WebDriverIO and preview providers get DOM snapshot support for free.
The
markAPI already fires at all the right moments — this is about capturing DOM state at those existing hook points and rendering it in Vitest's own viewer:page.mark(name)— explicit markslocator.mark(name)— marks with element selectorexpect.element()settlement — automatic marks after DOM assertionsrunner.onAfterRetryTask— marks on test retryValidations