Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:Microsoft Playwright Analyze Test Execution

From Leeroopedia
Knowledge Sources
Domains Debugging, Testing
Last Updated 2026-02-11 00:00 GMT

Overview

Parsing and modeling trace data to reconstruct test execution timelines, action trees, and failure analysis.

Description

Raw trace files are structured as newline-delimited JSON event streams stored in ZIP archives. To make this data useful for the trace viewer UI, it must be parsed, indexed, and modeled into a coherent representation of the test execution. This principle addresses the transformation from raw trace events into a structured trace model that supports timeline navigation, action tree rendering, snapshot lookup, and error analysis.

The analysis process involves several key transformations:

1. Multi-context merging:

A single test may produce multiple trace contexts: one from the test runner (recording test steps, assertions, hooks) and one or more from the library (recording browser API calls). These contexts use different clocks (client-side vs. server-side monotonic time) and must be aligned using a shared reference action to compute the time delta.

2. Action tree construction:

Actions have parent-child relationships (e.g., a test step containing multiple page interactions). The model builds a tree structure from flat action lists using parentId references, enabling hierarchical display in the viewer.

3. Error correlation:

Errors from test runner contexts and library contexts must be correlated. The model identifies the failed action (the innermost action that caused the failure) and associates error messages with source locations for display in the source panel.

4. Source mapping:

Stack frames from trace events are collected and associated with source file content (stored in the trace ZIP as resources/src@{sha1}.txt). This enables the viewer to display the test source code with error annotations.

5. Snapshot rendering:

DOM snapshots are reconstructed from the serialized node tree format into renderable HTML. This involves resolving node references (which point to nodes in previous snapshots for deduplication), rewriting URLs for the viewer's custom protocol handler, and injecting scripts for shadow DOM reconstruction and scroll position restoration.

Usage

Apply this principle when:

  • Building trace viewer UIs: The trace model is the data layer that powers all viewer functionality.
  • Programmatic trace analysis: Extracting metrics, generating reports, or performing automated analysis on trace data.
  • Comparing test runs: Using the structured model to diff execution timelines between passing and failing runs.
  • Understanding trace internals: Knowing the model structure helps when debugging trace viewer issues or extending its functionality.

Theoretical Basis

The trace analysis follows an ETL (Extract-Transform-Load) pattern:

// Extract: Parse raw trace files
function loadTrace(backend):
    contexts = []
    for each ordinal in backend.traceFiles:
        context = createEmptyContext()
        modernizer = new TraceModernizer(context)

        traceText = backend.readText(ordinal + '.trace')
        modernizer.appendTrace(traceText)

        networkText = backend.readText(ordinal + '.network')
        modernizer.appendTrace(networkText)

        stacksText = backend.readText(ordinal + '.stacks')
        if stacksText:
            applyCallMetadata(context, parseStacks(stacksText))

        contexts.append(context)
    return contexts

// Transform: Build the model
function buildTraceModel(traceUri, contexts):
    model = new TraceModel()

    // Merge and align timing across contexts
    model.actions = mergeActionsAndUpdateTiming(contexts)

    // Build derived data
    model.pages = collectPages(contexts)
    model.events = collectAndSortEvents(contexts)
    model.errors = collectErrors(contexts)
    model.errorDescriptors = correlateErrors(model)
    model.sources = collectSourceMaps(model.actions, model.errors)
    model.attachments = extractAttachments(model.actions)
    model.actionTree = buildActionTree(model.actions)

    return model

// Load: Render snapshots on demand
function renderSnapshot(renderer):
    html = traverseNodeTree(renderer.snapshot)
    html = rewriteURLs(html)
    html = injectViewerScripts(html)
    return { html, pageId, frameId }

Key design principles:

  • Lazy rendering: Snapshots are rendered on demand rather than pre-rendered, using an LRU cache to avoid redundant work. This keeps startup fast even for large traces.
  • Version modernization: A TraceModernizer transforms older trace formats into the current version, ensuring backward compatibility across Playwright versions.
  • Clock reconciliation: The time delta between test runner and library contexts is computed from the first shared action, then applied to all library context timestamps. This is necessary because the two contexts may run in different processes with different monotonic clocks.
  • Incremental loading: The backend interface (TraceLoaderBackend) is abstract, supporting both ZIP-based and directory-based trace sources. Progress callbacks enable UI feedback during loading.
  • Content-addressed storage: Resources are stored and retrieved by SHA1 hash, with content type information preserved for proper MIME-type serving.

Related Pages

Implemented By

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment