Skip to main content
@stacknext/playwright is an optional fixture package that connects Playwright scenarios to the server traces they produced. It injects W3C trace context into browser requests, waits for the corresponding collector traces, verifies the parent relationship and submits the sample to the active capture run. The package does not replace Playwright, capture screenshots or change test assertions. Without an active stacknext capture run it is a no-op.

Install

In the Next.js app:
The fixture requires @playwright/test 1.40 or newer and Node.js 20.9 or newer. Use the same Playwright version for the app and the fixture.

Configure Playwright

Correlation is verified per request, so captured runs must use one worker. Disable optional artifacts; StackNext never reads them and they only add CI noise.
baseURL should be the origin the browser actually visits. The fixture injects headers only for loopback URLs or for the origin in baseURL.

Use the fixture and annotation

Use the test exported by stackNextFixtures(), not a separately imported test, or the auto fixture will not be installed. stackNextFixtures() also exports the Playwright expect. The annotation is the preferred identity source. It is inherited by the test and appears in TestInfo.annotations. Use one annotation per test. The first annotation whose type starts with stacknext supplies the description. If none is present, Playwright’s stable test id is used, then file/title/project. Changing the annotation creates a new scenario with no baseline. Renaming the title or moving the test does not change an annotation-based scenario id.

Capture

With the app started through stacknext dev:
stacknext capture sets the run environment. Running playwright test directly without capture leaves the fixture idle. For a test-owned app, configure Playwright webServer; the server inherits the capture environment (STACKNEXT_TEST_RUN_ID, collector URL and token):
Then stacknext capture -- pnpm exec playwright test --workers=1 starts an ephemeral collector and lets Playwright start the app. Do not point the app at one collector while the fixture submits to another.

How correlation works

For each sample, the auto fixture:
  1. Creates a random W3C traceparent with a 32-hex trace id and 16-hex injected span id.
  2. Intercepts document, fetch and XHR requests. It injects the header only for loopback HTTP(S) URLs or the baseURL origin. Script, stylesheet, image and other resource requests are left alone.
  3. Allows the test to finish normally.
  4. Waits for the collector to return every injected document trace, polling at 150 ms after an initial settle delay.
  5. Submits the browser result, duration, retry/repeat index and up to 20 trace references to POST /api/test-runs/:id/samples.
The collector then:
  1. Looks up each trace in the current bounded store.
  2. Checks the trace id.
  3. Checks that at least one server span names the injected span id as its parent.
  4. Converts only verified traces into stored evidence.
  5. Marks the sample incomplete if any submitted trace is missing or fails the parent check.
A matching trace id alone is not accepted. There is no time-window guess, no “nearest request” fallback and no synthetic sample. A trace with no server span parented to the injected span is incomplete, not verified.
A document request made by the test is always submitted, even when its trace is missing, so missing document telemetry makes the sample incomplete. Optional fetch and XHR traces are included only when the collector finds them.

Environment variables

stacknext capture sets the first five variables for its child process. You normally do not set them yourself. The collector URL must be http://127.0.0.1, http://localhost or the IPv6 loopback form. HTTPS and non-loopback URLs are rejected.

What a sample stores

A sample contains:
  • scenario identity (id, source, title, file, project, tags);
  • Playwright status, expected status, retry and repeat index;
  • sample duration and capture time;
  • correlation status and reasons;
  • up to 20 verified traces with stable keys, durations and bounded spans, queries and errors;
  • deduplicated diagnostic finding references.
It does not contain browser storage, request/response bodies, headers, cookies, URL query values, SQL bind parameters, screenshots, video or Playwright trace archives.

Retries and sample counts

Playwright retries are recorded (retry, repeatEachIndex, status), but the comparison only uses verified samples. A flaky test that only passes on retry still leaves failed samples in the run and can make the comparison inconclusive. Recommended:
  • deterministic scenarios with explicit waits on visible UI;
  • retries: 0 for captured runs;
  • --repeat-each=3 or more;
  • --workers=1;
  • warm routes before capturing a baseline;
  • no shared mutable state between tests.

Troubleshooting incomplete samples

Parallel workers are not supported for captured runs. Keep workers: 1 until parallel correlation is explicitly documented as supported.

Security and privacy

  • The fixture talks only to a loopback collector over HTTP.
  • The bearer token is read from the environment and is never written into a test result, sample or comparison.
  • Injected traceparent values are random and contain no user or machine identifiers.
  • Scenario and trace keys are normalized and sanitized before storage.
  • The fixture is optional and runs no network code when capture is inactive.
See privacy and regression testing.