Module: lib/core/trace/replay

Deterministic replay of a recorded trace.

Replay drives the inputs a session received — events, navigations, resource settlements, and the non-deterministic globals the sandbox handed out — back into a real application, and then compares what the application did against what the recording says it did the first time.

That comparison is the whole point, and it is why replay records a trace of its own rather than simply asserting at the end. A replay that drove the inputs and then checked a final value could pass while every intermediate step was wrong. A replay that compares the observed write and DOM sequence step by step cannot.

Why observations are compared rather than trusted

A recording marks itself best-effort when it detects an escape it knows about: an unattributed write, a polling resource, a value it could not serialize. Those checks are real but not exhaustive — bridge modules are ordinary ES modules and are not sandboxed, so a Date.now() inside one is invisible to the recorder.

Replay therefore never trusts the recording's own claim. It re-derives determinism by running the framework for real and diffing. A trace that says "deterministic" and diverges fails loudly; a trace that says "best-effort" and reproduces perfectly is reported as such but still refuses to call itself verified unless the caller opts in.

Source:

Methods

(static) formatProblems(result) → {string}

Renders a replay's problems as a developer-readable report.

Parameters:
Name Type Description
result object

A replay result.

Source:
Returns:

The report.

Type
string

(static) replay(trace, options) → {Promise:.<object:>}

Replays a recorded trace against a live application.

Parameters:
Name Type Description
trace object

A trace produced by a recording.

options object

Replay options.

Properties
Name Type Attributes Description
mount function

Sets up and mounts the application. Whatever it returns is handed back to at as the context.

at function <optional>

Called after each input with (step, context), for the caller's own assertions.

root Document | Element <optional>

Where to resolve event targets. Defaults to the mounted subtree, falling back to document.

router object <optional>

A router to drive recorded navigations through.

allowBestEffort boolean <optional>

Accept a trace the recorder marked best-effort. Without this, replaying such a trace throws rather than reporting a pass it cannot stand behind.

strict boolean <optional>

Throw on divergence. Defaults to true.

Source:
Throws:

When the trace cannot be read, when it is best-effort and allowBestEffort was not set, or when replay diverged in strict mode.

Type
AvenxError
Returns:

The replay result.

Type
Promise:.<object:>

(inner) candidateRoots(context, explicitopt) → {Array:.<(Document:|Element:)>}

Builds the places an event target may be looked up, most specific first.

A test mount is not attached to the document — mountTestComponent mounts into a detached host — so resolving only against document would fail every replay run from a test. The mounted subtree is therefore searched first, and the document last, which also keeps a replay from reaching into unrelated markup that happens to match the same selector.

Parameters:
Name Type Attributes Description
context object | null

Whatever mount() returned.

explicit Document | Element <optional>

A root the caller supplied.

Source:
Returns:

Candidate roots.

Type
Array:.<(Document:|Element:)>

(inner) describeInput(input) → {string}

Describes a replayed input in one line.

Parameters:
Name Type Description
input object

The input node.

Source:
Returns:

A label such as click <button.qty-inc>.

Type
string

(inner) diff(expectedSigs, observedSigs) → {Object|null}

Compares an expected observation sequence against what replay saw.

Parameters:
Name Type Description
expectedSigs Array:.<string:>

Signatures from the recording.

observedSigs Array:.<string:>

Signatures from this run.

Source:
Returns:

The first point of difference, or null when the sequences match.

Type
Object | null

(inner) dispatchRecordedEvent(input, roots) → {Object}

Dispatches a recorded event against the live application.

Parameters:
Name Type Description
input object

The recorded event node.

roots Array:.<(Document:|Element:)>

Where to look for the target, in order.

Source:
Returns:

Whether the event could be delivered.

Type
Object

(inner) groupByInput(trace) → {Object}

Groups a trace's observations by the input that caused them.

Every node is walked up to its causal root; nodes rooted at input n belong to step n. Anything rooted elsewhere — an orphan left by truncation, an unattributed write — is collected separately, because it is evidence about the recording rather than about a step.

Parameters:
Name Type Description
trace object

The trace.

Source:
Returns:

Inputs with their observations.

Type
Object

(async, inner) settle() → {Promise:.<void:>}

Settles pending microtasks, the scheduler queue and one macrotask turn.

The scheduler's own nextTick covers batched component updates; the macrotask turn is what lets a resolved resource promise land. Implemented here rather than imported from the testing helpers so the replay engine does not depend on the DOM mock.

Source:
Returns:
Type
Promise:.<void:>

(inner) signature(node) → {string|null}

Reduces an observation node to the fields worth comparing.

Ids, timestamps and sequence numbers are excluded: they differ between two correct runs and comparing them would report divergence for every replay.

Parameters:
Name Type Description
node object

A recorded node.

Source:
Returns:

A comparable signature, or null for nodes not compared.

Type
string | null