@stacknext/playwright 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,66 @@
1
+ ---
2
+ title: Correlation
3
+ description: Exact trace injection, probing and the verified/incomplete sample rule.
4
+ ---
5
+
6
+ # Correlation
7
+
8
+ StackNext never links browser and server activity by time or proximity. Each
9
+ sample is proven by an injected trace context.
10
+
11
+ ## Injection
12
+
13
+ `createTraceparent()` generates a W3C `traceparent` with a new trace id and
14
+ span id. The fixture adds it to document, fetch and XHR requests whose URL is:
15
+
16
+ - loopback (`127.0.0.1`, `localhost`, `[::1]`, `::1`); or
17
+ - the Playwright project's `baseURL` origin.
18
+
19
+ Other resource types and cross-origin requests are left untouched.
20
+
21
+ ## Verification
22
+
23
+ The collector considers a trace verified only when both are true:
24
+
25
+ 1. it stored a trace with the injected trace id; and
26
+ 2. it contains a server span whose parent span id equals the injected span id.
27
+
28
+ <!-- coderabbit-ai-generated:v1 -->
29
+
30
+ <!-- coderabbit-ai-generated-section:v1:35e306be3c7839621b0cb18396b64a12651243d1d324f2c17b11b03ca80b9e99 -->
31
+
32
+ The fixture probes `GET /api/traces/:traceId` until the
33
+ document trace is found or the timeout expires. It submits at most 20 trace
34
+ references per sample, document requests first.
35
+
36
+ <!-- /coderabbit-ai-generated:v1 -->
37
+
38
+ If either condition is missing, the sample is `incomplete` with a reason such
39
+ as:
40
+
41
+ - `trace-not-found`;
42
+ - `injected-parent-not-found`;
43
+ - `no-request-trace-recorded`.
44
+
45
+ There is no fallback to a nearby request, a time window or a synthetic trace.
46
+ An incomplete sample makes the affected comparison inconclusive.
47
+
48
+ ## Why the server must cooperate
49
+
50
+ `@stacknext/next` installs the W3C composite propagator during registration. If
51
+ the app does not run StackNext instrumentation, or another provider replaces the
52
+ propagator, the injected trace id never reaches the server and correlation
53
+ fails.
54
+
55
+ The collector's self-instrumentation filter also excludes requests to
56
+ `/__stacknext/`, so dashboard and MCP traffic cannot be mistaken for application
57
+ requests.
58
+
59
+ ## Limits
60
+
61
+ - One worker only. Parallel correlation is not verified.
62
+ - Redirects and new tabs may create traces that are not in the submitted set.
63
+ - Browser-side rendering and network timing are not captured.
64
+ - Playwright screenshots, video and trace archives are never read or stored.
65
+
66
+ See [regression captures](../../regression/docs/captures.md).
@@ -0,0 +1,83 @@
1
+ ---
2
+ title: Fixture
3
+ description: How the auto stacknextCapture fixture identifies scenarios and submits samples.
4
+ ---
5
+
6
+ # Fixture
7
+
8
+ Import `test` and `expect` from `@stacknext/playwright` instead of
9
+ `@playwright/test`. The `stacknextCapture` fixture is automatic; you do not add
10
+ it to the test signature.
11
+
12
+ ## Capture lifecycle
13
+
14
+ 1. `resolveCaptureConfig()` reads the capture environment.
15
+ 2. If capture is inactive, the fixture is a no-op.
16
+ 3. During the test, document/fetch/XHR requests to loopback or the configured
17
+ `baseURL` origin receive a W3C `traceparent`.
18
+ 4. After the test, the fixture waits for the collector to observe the traces.
19
+ 5. It submits one sample with the Playwright status, duration, retry/repeat
20
+ indices and verified trace references.
21
+
22
+ Skipped tests do not submit a sample. The fixture never replaces Playwright
23
+ assertions or changes the test result.
24
+
25
+ ## Scenario identity
26
+
27
+ The preferred identity is an explicit annotation:
28
+
29
+ ```ts
30
+ import { test, expect } from '@stacknext/playwright'
31
+
32
+ test('checkout completes', async ({ page }) => {
33
+ test.info().annotations.push({
34
+ type: 'stacknext.scenario',
35
+ description: 'checkout-complete',
36
+ })
37
+
38
+ await page.goto('/checkout')
39
+ await expect(page.getByRole('heading', { name: 'Checkout' })).toBeVisible()
40
+ })
41
+ ```
42
+
43
+ The fixture accepts any annotation whose type starts with `stacknext` and uses
44
+ its description. If none exists, identity falls back to the Playwright `testId`,
45
+ then file + title + project.
46
+
47
+ Keep the annotation stable. Changing it creates a new scenario with no matching
48
+ baseline.
49
+
50
+ ## Capture environment
51
+
52
+ The fixture reads:
53
+
54
+ | Variable | Default | Meaning |
55
+ | --- | --- | --- |
56
+ | `STACKNEXT_TEST_RUN_ID` | required when active | Active `run-...` id. |
57
+ | `STACKNEXT_COLLECTOR_URL` | required when active | Loopback collector origin. |
58
+ | `STACKNEXT_TOKEN` | required when active | Collector bearer token. |
59
+ | `STACKNEXT_CAPTURE_SETTLE_MS` | 500 | Wait before the first probe. |
60
+ | `STACKNEXT_CAPTURE_TIMEOUT_MS` | 5000 | Probe deadline per sample. |
61
+
62
+ `stacknext capture` sets the required values. Do not set them by hand for a
63
+ normal captured run.
64
+
65
+ ## Playwright configuration
66
+
67
+ - Use **one worker** for captured runs.
68
+ - Use at least three samples per scenario for a comparison
69
+ (`--repeat-each=3`).
70
+ - Warm routes before capturing a baseline.
71
+ - Keep the test command short and deterministic.
72
+
73
+ ## Exports
74
+
75
+ <!-- coderabbit-ai-generated:v1 -->
76
+
77
+ <!-- coderabbit-ai-generated-section:v1:9b1d429fc146b7836cdccc75d58c560d2e60b18305797d98bcd9841b60c57664 -->
78
+
79
+ `stackNextFixtures()` is an exported function returning `{ test, expect }`. `resolveCaptureConfig()` returns a
80
+ `CaptureConfig` or `null`; it throws `CaptureTransportError` when capture is
81
+ active but the required values are invalid.
82
+
83
+ <!-- /coderabbit-ai-generated:v1 -->
package/docs/index.md ADDED
@@ -0,0 +1,100 @@
1
+ ---
2
+ title: "@stacknext/playwright"
3
+ description: Optional Playwright fixtures that correlate browser scenarios with StackNext server telemetry.
4
+ ---
5
+
6
+ # @stacknext/playwright
7
+
8
+ `@stacknext/playwright` provides a drop-in Playwright `test` fixture. During
9
+ `stacknext capture`, it injects W3C trace context into browser requests, probes
10
+ the collector for the resulting server trace and submits verified samples for
11
+ the scenario.
12
+
13
+ ## Who should read this
14
+
15
+ Teams using runtime regression testing. This is an **optional public
16
+ integration package**; projects that do not capture Playwright runs do not need
17
+ it.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pnpm add -D @stacknext/playwright @playwright/test
23
+ ```
24
+
25
+ `@playwright/test >=1.40.0 <2` is an optional peer dependency. The package is
26
+ inert outside an active capture run.
27
+
28
+ ## Basic setup
29
+
30
+ <!-- coderabbit-ai-generated:v1 -->
31
+
32
+ <!-- coderabbit-ai-generated-section:v1:330156cdeba17c62fdd7205ba9dfb6a1e4eeadd469e4d3cbdc5b72304a6c1817 -->
33
+
34
+ ```ts
35
+ // playwright.config.ts
36
+ import { defineConfig } from '@playwright/test'
37
+
38
+ export default defineConfig({
39
+ testDir: './e2e',
40
+ workers: 1,
41
+ use: { baseURL: 'http://127.0.0.1:4402' },
42
+ })
43
+ ```
44
+
45
+ <!-- /coderabbit-ai-generated:v1 -->
46
+
47
+ ```ts
48
+ // e2e/checkout.spec.ts
49
+ import { test, expect } from '@stacknext/playwright'
50
+
51
+ test('checkout completes', async ({ page }) => {
52
+ await page.goto('/checkout')
53
+ await expect(page.getByRole('heading', { name: 'Checkout' })).toBeVisible()
54
+ })
55
+ ```
56
+
57
+ <!-- coderabbit-ai-generated:v1 -->
58
+
59
+ <!-- coderabbit-ai-generated-section:v1:7abbb61d09c1a8f57748d7bf54218ee490f41f98fa4dc39ad4aef8304527a5f6 -->
60
+
61
+ Set `use.baseURL` to your running app’s actual origin (the example app uses
62
+ `http://127.0.0.1:4402`). Run it through the CLI so the capture environment exists:
63
+
64
+ <!-- /coderabbit-ai-generated:v1 -->
65
+
66
+ ```bash
67
+ stacknext capture --name baseline -- \
68
+ pnpm exec playwright test --workers=1 --repeat-each=3
69
+ ```
70
+
71
+ Running `playwright test` directly does not capture or compare anything.
72
+
73
+ ## Exports
74
+
75
+ <!-- coderabbit-ai-generated:v1 -->
76
+
77
+ <!-- coderabbit-ai-generated-section:v1:b5db70b760e7288ddbd50c6826a786bb63e51a6bb4cfbf97d44192f11f505f50 -->
78
+
79
+ | Export | Purpose |
80
+ | --- | --- |
81
+ | `test` | Playwright test with the auto `stacknextCapture` fixture. |
82
+ | `expect` | Re-exported Playwright expect. |
83
+ | `stackNextFixtures` | Exported function returning `{ test, expect }`. |
84
+ | `resolveCaptureConfig` | Reads and validates capture environment variables. |
85
+ | `CaptureTransportError` | Capture configuration/transport error. |
86
+ | `createTraceparent` | Creates a W3C trace context pair. |
87
+
88
+ <!-- /coderabbit-ai-generated:v1 -->
89
+
90
+ ## Documentation map
91
+
92
+ - [Fixture](fixture.md) — annotations, identity and capture lifecycle.
93
+ - [Correlation](correlation.md) — injection, probing and verified samples.
94
+ - [Troubleshooting](troubleshooting.md) — missing samples and incomplete runs.
95
+
96
+ ## Related packages
97
+
98
+ - `@stacknext/regression` owns scenario identity and sample schemas.
99
+ - `@stacknext/cli` starts the collector and writes run records.
100
+ - `@stacknext/next` receives the injected trace on the server.
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: Troubleshooting
3
+ description: Fix missing samples, failed correlation and inactive capture fixtures.
4
+ ---
5
+
6
+ # Troubleshooting
7
+
8
+ ## The fixture does nothing
9
+
10
+ `resolveCaptureConfig()` returns `null` when capture is inactive. That is normal
11
+ for a direct `playwright test` run. Start the test through:
12
+
13
+ ```bash
14
+ stacknext capture --name candidate -- pnpm exec playwright test --workers=1
15
+ ```
16
+
17
+ ## `CaptureTransportError`
18
+
19
+ The run is marked active but the environment is invalid. Check that
20
+ `STACKNEXT_TEST_RUN_ID` matches `run-<16 hex>`,
21
+ `STACKNEXT_COLLECTOR_URL` is a loopback URL and `STACKNEXT_TOKEN` is present.
22
+ Do not set these manually; let `stacknext capture` supply them.
23
+
24
+ ## Samples are incomplete
25
+
26
+ 1. Confirm the app was started with StackNext instrumentation. The server must
27
+ have an active OTel provider and the W3C propagator.
28
+ 2. Check that the browser request URL is loopback or matches `baseURL`.
29
+ 3. Look at the sample's correlation reason in `stacknext runs show <run-id>` or
30
+ the MCP `stacknext_get_test_run` response.
31
+ 4. Confirm the app received the request before the probe timeout. Increase
32
+ `STACKNEXT_CAPTURE_TIMEOUT_MS` only when the app is genuinely slow to start.
33
+ 5. Run with one worker. Parallel workers are not supported for capture.
34
+
35
+ ## A scenario has no baseline match
36
+
37
+ The scenario identity changed. Prefer a stable `stacknext.scenario` annotation
38
+ and keep it unchanged between the baseline and candidate. See
39
+ [Fixture](fixture.md).
40
+
41
+ ## The test passes but the run exits 3
42
+
43
+ Exit 3 means the child command succeeded but the captured telemetry is
44
+ incomplete. It is not a pass. Inspect the run status and sample correlation
45
+ before comparing.
46
+
47
+ ## Timeouts
48
+
49
+ - `STACKNEXT_CAPTURE_SETTLE_MS` (default 500) delays the first probe.
50
+ - `STACKNEXT_CAPTURE_TIMEOUT_MS` (default 5000) bounds probing.
51
+
52
+ Very slow development servers may need a larger timeout, but a consistently
53
+ missing document trace usually indicates broken instrumentation, not a short
54
+ timeout.
55
+
56
+ ## Verify
57
+
58
+ ```bash
59
+ stacknext runs list --json
60
+ stacknext runs show <run-id> --json
61
+ stacknext doctor
62
+ ```
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@stacknext/playwright",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Playwright fixtures that correlate browser scenarios with StackNext server telemetry",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "files": [
8
- "dist"
8
+ "dist",
9
+ "docs"
9
10
  ],
10
11
  "main": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts",
@@ -18,7 +19,7 @@
18
19
  "./package.json": "./package.json"
19
20
  },
20
21
  "dependencies": {
21
- "@stacknext/regression": "0.8.0"
22
+ "@stacknext/regression": "0.10.0"
22
23
  },
23
24
  "peerDependencies": {
24
25
  "@playwright/test": ">=1.40.0 <2"