@stacknext/playwright 0.0.0-stage → 0.6.1
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.
- package/LICENSE +21 -0
- package/README.md +29 -2
- package/dist/collector-client.d.ts +24 -0
- package/dist/collector-client.d.ts.map +1 -0
- package/dist/collector-client.js +103 -0
- package/dist/collector-client.js.map +1 -0
- package/dist/fixture.d.ts +15 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +165 -0
- package/dist/fixture.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/traceparent.d.ts +11 -0
- package/dist/traceparent.d.ts.map +1 -0
- package/dist/traceparent.js +21 -0
- package/dist/traceparent.js.map +1 -0
- package/package.json +59 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StackNext contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @stacknext/playwright
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Optional Playwright fixtures that correlate browser scenarios with verified
|
|
4
|
+
StackNext server traces.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { stackNextFixtures } from '@stacknext/playwright'
|
|
8
|
+
|
|
9
|
+
const { test, expect } = stackNextFixtures()
|
|
10
|
+
|
|
11
|
+
test(
|
|
12
|
+
'renders the overview',
|
|
13
|
+
{ annotation: { type: 'stacknext.scenario', description: 'app.overview' } },
|
|
14
|
+
async ({ page }) => {
|
|
15
|
+
await page.goto('/')
|
|
16
|
+
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible()
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The fixture injects W3C trace context into loopback and `baseURL` requests and
|
|
22
|
+
is inert outside an active `stacknext capture` run. A sample is verified only
|
|
23
|
+
when the collector finds the injected trace and a server span parented to the
|
|
24
|
+
injected span id. There is no time-window fallback.
|
|
25
|
+
|
|
26
|
+
Captured runs must use one Playwright worker. The package is ESM-only, requires
|
|
27
|
+
Node.js 20.9 or newer, and has an optional `@playwright/test` peer dependency
|
|
28
|
+
(1.40 or newer).
|
|
29
|
+
|
|
30
|
+
License: MIT.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SampleSubmission, ScenarioIdentity } from '@stacknext/regression';
|
|
2
|
+
export interface CaptureConfig {
|
|
3
|
+
runId: string;
|
|
4
|
+
collectorUrl: string;
|
|
5
|
+
token: string;
|
|
6
|
+
settleMs: number;
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class CaptureTransportError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolves capture state from the environment. Nothing is captured unless the
|
|
14
|
+
* capture command explicitly started a test run.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveCaptureConfig(env?: NodeJS.ProcessEnv): CaptureConfig | null;
|
|
17
|
+
export interface TraceProbe {
|
|
18
|
+
found: boolean;
|
|
19
|
+
spanCount: number;
|
|
20
|
+
}
|
|
21
|
+
/** Checks whether a correlated trace has reached the collector store yet. */
|
|
22
|
+
export declare function probeTrace(config: CaptureConfig, traceId: string): Promise<TraceProbe>;
|
|
23
|
+
export declare function submitSample(config: CaptureConfig, scenario: ScenarioIdentity, sample: SampleSubmission): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=collector-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector-client.d.ts","sourceRoot":"","sources":["../src/collector-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE/E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,aAAa,GAAG,IAAI,CA6BtB;AA4BD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,6EAA6E;AAC7E,wBAAsB,UAAU,CAC9B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC,CAarB;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export class CaptureTransportError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'CaptureTransportError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function loopbackHost(hostname) {
|
|
8
|
+
return (hostname === '127.0.0.1' ||
|
|
9
|
+
hostname === 'localhost' ||
|
|
10
|
+
hostname === '[::1]' ||
|
|
11
|
+
hostname === '::1');
|
|
12
|
+
}
|
|
13
|
+
function positiveNumber(value, fallback) {
|
|
14
|
+
if (!value)
|
|
15
|
+
return fallback;
|
|
16
|
+
const parsed = Number(value);
|
|
17
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves capture state from the environment. Nothing is captured unless the
|
|
21
|
+
* capture command explicitly started a test run.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveCaptureConfig(env = process.env) {
|
|
24
|
+
const runId = env.STACKNEXT_TEST_RUN_ID?.trim();
|
|
25
|
+
if (!runId)
|
|
26
|
+
return null;
|
|
27
|
+
if (!/^run-[0-9a-f]{16}$/.test(runId)) {
|
|
28
|
+
throw new CaptureTransportError('STACKNEXT_TEST_RUN_ID is not a valid StackNext run id');
|
|
29
|
+
}
|
|
30
|
+
const collectorUrl = env.STACKNEXT_COLLECTOR_URL?.trim() ?? '';
|
|
31
|
+
const token = env.STACKNEXT_TOKEN?.trim() ?? '';
|
|
32
|
+
if (!collectorUrl || !token) {
|
|
33
|
+
throw new CaptureTransportError('STACKNEXT_COLLECTOR_URL and STACKNEXT_TOKEN are required when capture is active');
|
|
34
|
+
}
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(collectorUrl);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new CaptureTransportError('STACKNEXT_COLLECTOR_URL is not a valid URL');
|
|
41
|
+
}
|
|
42
|
+
if (url.protocol !== 'http:' || !loopbackHost(url.hostname)) {
|
|
43
|
+
throw new CaptureTransportError('StackNext capture only connects to a loopback HTTP collector');
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
runId,
|
|
47
|
+
collectorUrl: url.origin,
|
|
48
|
+
token,
|
|
49
|
+
settleMs: positiveNumber(env.STACKNEXT_CAPTURE_SETTLE_MS, 500),
|
|
50
|
+
timeoutMs: positiveNumber(env.STACKNEXT_CAPTURE_TIMEOUT_MS, 5_000),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function request(config, pathname, init = {}) {
|
|
54
|
+
let response;
|
|
55
|
+
try {
|
|
56
|
+
response = await fetch(`${config.collectorUrl}${pathname}`, {
|
|
57
|
+
...init,
|
|
58
|
+
headers: {
|
|
59
|
+
authorization: `Bearer ${config.token}`,
|
|
60
|
+
...(init.body ? { 'content-type': 'application/json' } : {}),
|
|
61
|
+
...(init.headers ?? {}),
|
|
62
|
+
},
|
|
63
|
+
signal: AbortSignal.timeout(Math.max(config.timeoutMs, 1_000)),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw new CaptureTransportError(`Could not reach the StackNext collector at ${config.collectorUrl}: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
}
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
/** Checks whether a correlated trace has reached the collector store yet. */
|
|
72
|
+
export async function probeTrace(config, traceId) {
|
|
73
|
+
const response = await request(config, `/api/traces/${traceId}`);
|
|
74
|
+
if (response.status === 404)
|
|
75
|
+
return { found: false, spanCount: 0 };
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new CaptureTransportError(`Collector rejected trace lookup with HTTP ${response.status}`);
|
|
78
|
+
}
|
|
79
|
+
const payload = (await response.json());
|
|
80
|
+
return {
|
|
81
|
+
found: true,
|
|
82
|
+
spanCount: Array.isArray(payload.spans) ? payload.spans.length : 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export async function submitSample(config, scenario, sample) {
|
|
86
|
+
const response = await request(config, `/api/test-runs/${config.runId}/samples`, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
body: JSON.stringify({ scenario, sample }),
|
|
89
|
+
});
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
let detail = '';
|
|
92
|
+
try {
|
|
93
|
+
const payload = (await response.json());
|
|
94
|
+
if (payload.error)
|
|
95
|
+
detail = `: ${payload.error}`;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Keep the status-only message.
|
|
99
|
+
}
|
|
100
|
+
throw new CaptureTransportError(`Collector rejected the captured sample with HTTP ${response.status}${detail}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=collector-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector-client.js","sourceRoot":"","sources":["../src/collector-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
export { expect };
|
|
3
|
+
type StackNextFixtures = {
|
|
4
|
+
stacknextCapture: void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Auto fixture that injects W3C trace context into same-origin browser requests
|
|
8
|
+
* and submits only verified, collector-backed evidence for this test.
|
|
9
|
+
*/
|
|
10
|
+
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & StackNextFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
11
|
+
export declare function stackNextFixtures(): {
|
|
12
|
+
test: typeof test;
|
|
13
|
+
expect: typeof expect;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAiB,MAAM,kBAAkB,CAAA;AAEtE,OAAO,EAAE,MAAM,EAAE,CAAA;AAmJjB,KAAK,iBAAiB,GAAG;IACvB,gBAAgB,EAAE,IAAI,CAAA;CACvB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,iQA4Cf,CAAA;AAEF,wBAAgB,iBAAiB,IAAI;IAAE,IAAI,EAAE,OAAO,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,MAAM,CAAA;CAAE,CAEhF"}
|
package/dist/fixture.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { test as base, expect } from '@playwright/test';
|
|
2
|
+
export { expect };
|
|
3
|
+
import { createSampleId, scenarioIdentity, } from '@stacknext/regression';
|
|
4
|
+
import { probeTrace, resolveCaptureConfig, submitSample, } from './collector-client.js';
|
|
5
|
+
import { createTraceparent } from './traceparent.js';
|
|
6
|
+
const INJECTED_TYPES = new Set(['document', 'fetch', 'xhr']);
|
|
7
|
+
const MAX_TRACES = 20;
|
|
8
|
+
function sleep(ms) {
|
|
9
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
}
|
|
11
|
+
function loopbackHost(hostname) {
|
|
12
|
+
return (hostname === '127.0.0.1' ||
|
|
13
|
+
hostname === 'localhost' ||
|
|
14
|
+
hostname === '[::1]' ||
|
|
15
|
+
hostname === '::1');
|
|
16
|
+
}
|
|
17
|
+
function shouldInject(rawUrl, baseURL) {
|
|
18
|
+
let url;
|
|
19
|
+
try {
|
|
20
|
+
url = new URL(rawUrl);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
26
|
+
return false;
|
|
27
|
+
if (loopbackHost(url.hostname))
|
|
28
|
+
return true;
|
|
29
|
+
if (!baseURL)
|
|
30
|
+
return false;
|
|
31
|
+
try {
|
|
32
|
+
return new URL(baseURL).origin === url.origin;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function scenarioAnnotation(testInfo) {
|
|
39
|
+
for (const annotation of testInfo.annotations) {
|
|
40
|
+
if (!annotation.type.startsWith('stacknext'))
|
|
41
|
+
continue;
|
|
42
|
+
const description = annotation.description?.trim();
|
|
43
|
+
if (description)
|
|
44
|
+
return description;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
function identityFor(testInfo) {
|
|
49
|
+
return scenarioIdentity({
|
|
50
|
+
title: testInfo.title,
|
|
51
|
+
file: testInfo.file,
|
|
52
|
+
project: testInfo.project.name,
|
|
53
|
+
tags: testInfo.tags,
|
|
54
|
+
testId: testInfo.testId,
|
|
55
|
+
annotation: scenarioAnnotation(testInfo),
|
|
56
|
+
rootDir: testInfo.config.rootDir,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function waitForInjectedTraces(config, injected) {
|
|
60
|
+
const found = new Map();
|
|
61
|
+
const documents = injected.filter((request) => request.resourceType === 'document');
|
|
62
|
+
const deadline = Date.now() + config.timeoutMs;
|
|
63
|
+
await sleep(config.settleMs);
|
|
64
|
+
const inspect = async () => {
|
|
65
|
+
for (const request of injected) {
|
|
66
|
+
if (found.has(request.traceId))
|
|
67
|
+
continue;
|
|
68
|
+
const probe = await probeTrace(config, request.traceId);
|
|
69
|
+
if (probe.found && probe.spanCount > 0)
|
|
70
|
+
found.set(request.traceId, probe.spanCount);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
await inspect();
|
|
74
|
+
while (Date.now() < deadline &&
|
|
75
|
+
documents.some((request) => !found.has(request.traceId))) {
|
|
76
|
+
await sleep(150);
|
|
77
|
+
await inspect();
|
|
78
|
+
}
|
|
79
|
+
return found;
|
|
80
|
+
}
|
|
81
|
+
async function captureSample(config, testInfo, injected) {
|
|
82
|
+
const found = await waitForInjectedTraces(config, injected);
|
|
83
|
+
const ordered = [...injected].sort((left, right) => {
|
|
84
|
+
const leftDocument = left.resourceType === 'document' ? 0 : 1;
|
|
85
|
+
const rightDocument = right.resourceType === 'document' ? 0 : 1;
|
|
86
|
+
return leftDocument - rightDocument || left.sequence - right.sequence;
|
|
87
|
+
});
|
|
88
|
+
const references = ordered
|
|
89
|
+
.filter((request) => request.resourceType === 'document' || found.has(request.traceId))
|
|
90
|
+
.slice(0, MAX_TRACES)
|
|
91
|
+
.map((request) => ({
|
|
92
|
+
traceId: request.traceId,
|
|
93
|
+
injectedSpanId: request.spanId,
|
|
94
|
+
}));
|
|
95
|
+
const sample = {
|
|
96
|
+
id: createSampleId(),
|
|
97
|
+
status: testInfo.status === 'timedOut' ||
|
|
98
|
+
testInfo.status === 'interrupted' ||
|
|
99
|
+
testInfo.status === 'failed'
|
|
100
|
+
? testInfo.status
|
|
101
|
+
: 'passed',
|
|
102
|
+
expectedStatus: testInfo.expectedStatus === 'failed' || testInfo.expectedStatus === 'skipped'
|
|
103
|
+
? testInfo.expectedStatus
|
|
104
|
+
: 'passed',
|
|
105
|
+
retry: testInfo.retry,
|
|
106
|
+
repeatEachIndex: testInfo.repeatEachIndex,
|
|
107
|
+
durationMs: testInfo.duration,
|
|
108
|
+
capturedAt: Date.now(),
|
|
109
|
+
};
|
|
110
|
+
await submitSample(config, identityFor(testInfo), { ...sample, traces: references });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Auto fixture that injects W3C trace context into same-origin browser requests
|
|
114
|
+
* and submits only verified, collector-backed evidence for this test.
|
|
115
|
+
*/
|
|
116
|
+
export const test = base.extend({
|
|
117
|
+
stacknextCapture: [
|
|
118
|
+
async ({ context }, use, testInfo) => {
|
|
119
|
+
const config = resolveCaptureConfig();
|
|
120
|
+
if (!config) {
|
|
121
|
+
await use();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
let sequence = 0;
|
|
125
|
+
const injected = [];
|
|
126
|
+
const baseURL = testInfo.project.use.baseURL;
|
|
127
|
+
await context.route('**/*', async (route) => {
|
|
128
|
+
const request = route.request();
|
|
129
|
+
if (!INJECTED_TYPES.has(request.resourceType())) {
|
|
130
|
+
await route.fallback();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!shouldInject(request.url(), baseURL)) {
|
|
134
|
+
await route.fallback();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const trace = createTraceparent();
|
|
138
|
+
injected.push({
|
|
139
|
+
traceId: trace.traceId,
|
|
140
|
+
spanId: trace.spanId,
|
|
141
|
+
resourceType: request.resourceType(),
|
|
142
|
+
url: request.url(),
|
|
143
|
+
sequence,
|
|
144
|
+
});
|
|
145
|
+
sequence += 1;
|
|
146
|
+
await route.fallback({
|
|
147
|
+
headers: {
|
|
148
|
+
...request.headers(),
|
|
149
|
+
traceparent: trace.traceparent,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
await use();
|
|
154
|
+
await context.unroute('**/*');
|
|
155
|
+
if (testInfo.status === 'skipped')
|
|
156
|
+
return;
|
|
157
|
+
await captureSample(config, testInfo, injected);
|
|
158
|
+
},
|
|
159
|
+
{ auto: true },
|
|
160
|
+
],
|
|
161
|
+
});
|
|
162
|
+
export function stackNextFixtures() {
|
|
163
|
+
return { test, expect };
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture.js","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { test, expect, stackNextFixtures } from './fixture.js';
|
|
2
|
+
export { resolveCaptureConfig, CaptureTransportError, type CaptureConfig, } from './collector-client.js';
|
|
3
|
+
export { createTraceparent, type InjectedTraceContext } from './traceparent.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,aAAa,GACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GAEtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,iBAAiB,EAA6B,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface InjectedTraceContext {
|
|
2
|
+
traceId: string;
|
|
3
|
+
spanId: string;
|
|
4
|
+
traceparent: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Creates a W3C trace context for one browser request. The child span id is
|
|
8
|
+
* what proves server correlation: Next.js must parent a server span to it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createTraceparent(): InjectedTraceContext;
|
|
11
|
+
//# sourceMappingURL=traceparent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceparent.d.ts","sourceRoot":"","sources":["../src/traceparent.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;CACpB;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,oBAAoB,CAQxD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
function nonZeroHex(bytes) {
|
|
3
|
+
const buffer = randomBytes(bytes);
|
|
4
|
+
if (buffer.every((value) => value === 0))
|
|
5
|
+
buffer[bytes - 1] = 1;
|
|
6
|
+
return buffer.toString('hex');
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates a W3C trace context for one browser request. The child span id is
|
|
10
|
+
* what proves server correlation: Next.js must parent a server span to it.
|
|
11
|
+
*/
|
|
12
|
+
export function createTraceparent() {
|
|
13
|
+
const traceId = nonZeroHex(16);
|
|
14
|
+
const spanId = nonZeroHex(8);
|
|
15
|
+
return {
|
|
16
|
+
traceId,
|
|
17
|
+
spanId,
|
|
18
|
+
traceparent: `00-${traceId}-${spanId}-01`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=traceparent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceparent.js","sourceRoot":"","sources":["../src/traceparent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAQzC,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IACjC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC;QAAE,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IAC/D,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;IAC5B,OAAO;QACL,OAAO;QACP,MAAM;QACN,WAAW,EAAE,MAAM,OAAO,IAAI,MAAM,KAAK;KAC1C,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacknext/playwright",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Playwright fixtures that correlate browser scenarios with StackNext server telemetry",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@stacknext/regression": "0.6.1"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@playwright/test": ">=1.40.0 <2"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@playwright/test": "1.58.2"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20.9.0"
|
|
31
|
+
},
|
|
32
|
+
"author": "StackNext contributors",
|
|
33
|
+
"homepage": "https://github.com/marrrkkk/stacknext#readme",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/marrrkkk/stacknext.git",
|
|
37
|
+
"directory": "packages/playwright"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/marrrkkk/stacknext/issues"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"stacknext",
|
|
44
|
+
"nextjs",
|
|
45
|
+
"playwright",
|
|
46
|
+
"testing",
|
|
47
|
+
"tracing",
|
|
48
|
+
"regression-testing"
|
|
49
|
+
],
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"@playwright/test": {
|
|
55
|
+
"optional": true
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsc -p tsconfig.build.json",
|
|
60
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
61
|
+
}
|
|
6
62
|
}
|