@tracelane/wdio 0.1.0-alpha.15 → 0.1.0-alpha.17
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/README.md +2 -2
- package/dist/options.d.ts +1 -1
- package/dist/options.d.ts.map +1 -1
- package/dist/tracelane-session.d.ts.map +1 -1
- package/dist/tracelane-session.js +3 -5
- package/dist/tracelane-session.js.map +1 -1
- package/package.json +3 -3
- package/dist/inpage-bundle.d.ts +0 -9
- package/dist/inpage-bundle.d.ts.map +0 -1
- package/dist/inpage-bundle.js +0 -47
- package/dist/inpage-bundle.js.map +0 -1
- package/dist/network-capture.d.ts +0 -38
- package/dist/network-capture.d.ts.map +0 -1
- package/dist/network-capture.js +0 -124
- package/dist/network-capture.js.map +0 -1
- package/dist/report-writer.d.ts +0 -38
- package/dist/report-writer.d.ts.map +0 -1
- package/dist/report-writer.js +0 -56
- package/dist/report-writer.js.map +0 -1
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ export const config: Options.Testrunner = {
|
|
|
87
87
|
## How it works
|
|
88
88
|
|
|
89
89
|
- On the first test, the Service injects an rrweb recorder bundle into the page and installs an in-page event buffer (`window.__tracelane__events`).
|
|
90
|
-
- The Node side drains that buffer on a poll (default every
|
|
90
|
+
- The Node side drains that buffer on a poll (default every 500 ms) and on every `afterTest`, re-injecting after each navigation.
|
|
91
91
|
- In `failed` mode (default) a passing test discards its buffer; a failing test's buffer is handed to [`@tracelane/report`](https://github.com/Cubenest/rrweb-stack/tree/main/packages/tracelane-report), which builds the single offline HTML (≤ 25 MB).
|
|
92
92
|
|
|
93
93
|
## Options
|
|
@@ -100,7 +100,7 @@ export const config: Options.Testrunner = {
|
|
|
100
100
|
| `capture.network` | `boolean` | `true` | Capture network requests via the in-page `rrweb/network@1` plugin — all browsers, no CDP. Privacy-first: only URL/method/status/timing by default (headers + bodies off; opt in via `capture.networkOptions`). CDP is an optional fallback that adds authoritative status + true no-response failures where it's available. |
|
|
101
101
|
| `capture.networkOptions` | `NetworkRecordOptions` | plugin defaults | Forwarded to the in-page network plugin (`recordHeaders`, `recordBody`, `maskRequestFn`, `payloadHostDenyList`, …). Defaults are privacy-first (headers + bodies off). Ignored when `capture.network` is `false`. |
|
|
102
102
|
| `capture.console` | `boolean` | `true` | Capture `console.*` via the rrweb console plugin. Setting this `false` also drops any `[tracelane.net]` network-error lines from the CDP fallback path, since those surface through `console.error`. |
|
|
103
|
-
| `drainIntervalMs` | `number` | `
|
|
103
|
+
| `drainIntervalMs` | `number` | `500` | Node-side drain poll interval. |
|
|
104
104
|
| `cooldownMs` | `number` | `250` | Re-injection cooldown guard (suppresses double-init on hash/HMR navigation). |
|
|
105
105
|
| `allure` | `boolean` | `false` | Reserved for the v1.1 Allure shim. No-op in v1. |
|
|
106
106
|
| `visualDiff` | `boolean` | `false` | Reserved for the post-MVP visual-diff add-on. No-op in v1. |
|
package/dist/options.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface TraceLaneOptions {
|
|
|
61
61
|
capture?: CaptureOptions;
|
|
62
62
|
/** Reserved for the post-MVP visual-diff add-on (P1 PRD §H). No-op in v1. */
|
|
63
63
|
visualDiff?: boolean;
|
|
64
|
-
/** Node-side drain poll interval in ms (ADR-0006). Default
|
|
64
|
+
/** Node-side drain poll interval in ms (ADR-0006). Default 500 (from @tracelane/core when unset). */
|
|
65
65
|
drainIntervalMs?: number;
|
|
66
66
|
/** Re-injection cooldown guard in ms (ADR-0006). Default 250. */
|
|
67
67
|
cooldownMs?: number;
|
package/dist/options.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElE,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElE,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qGAAqG;IACrG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;;;OAMG;IACH,MAAM,CAAC,EAAE;QACP,gDAAgD;QAChD,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,gDAAgD;AAChD,eAAO,MAAM,eAAe,wBAAwB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracelane-session.d.ts","sourceRoot":"","sources":["../src/tracelane-session.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"tracelane-session.d.ts","sourceRoot":"","sources":["../src/tracelane-session.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,oBAAoB,CAAC;AAQ1E,qFAAqF;AACrF,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,+EAA+E;AAC/E,KAAK,cAAc,GAAG,WAAW,GAAG;IAClC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,GAAG,CAAqB;IAEhC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,eAAe,CAAS;IAChC,6EAA6E;IAC7E,OAAO,CAAC,kBAAkB,CAAS;gBAEvB,OAAO,GAAE,gBAAqB,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;IAW5E,iFAAiF;IACjF,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIjD,+EAA+E;IAC/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIrC;;;;OAIG;IACG,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD;;;;;;OAMG;IACH,OAAO,CAAC,2BAA2B;IAKnC,sEAAsE;IACtE,OAAO,CAAC,4BAA4B;IA6BpC,iFAAiF;IAC3E,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/D;;;;;OAKG;YACW,yBAAyB;IAevC;;;;;;;;OAQG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC;;;;;;OAMG;IACG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA6BnF;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B,gFAAgF;IAChF,OAAO,CAAC,SAAS;CAclB"}
|
|
@@ -5,12 +5,10 @@
|
|
|
5
5
|
// the capture/inject/drain/report logic lives in exactly one place (ADR-0004:
|
|
6
6
|
// "the same logic exported as plain hook functions"). The session owns the
|
|
7
7
|
// recorder, the current-test metadata, and the report-write decision.
|
|
8
|
-
import { createRecorder, } from '@tracelane/core';
|
|
8
|
+
import { attachNetworkCapture, createRecorder, loadRrwebBundle, } from '@tracelane/core';
|
|
9
|
+
import { writeReport } from '@tracelane/report';
|
|
9
10
|
import { normalizeResult } from './framework-result.js';
|
|
10
|
-
import { loadRrwebBundle } from './inpage-bundle.js';
|
|
11
|
-
import { attachNetworkCapture } from './network-capture.js';
|
|
12
11
|
import { DEFAULT_OUT_DIR } from './options.js';
|
|
13
|
-
import { writeReport } from './report-writer.js';
|
|
14
12
|
import { createWdioExecutor } from './wdio-executor.js';
|
|
15
13
|
export class TraceLaneSession {
|
|
16
14
|
options;
|
|
@@ -70,7 +68,7 @@ export class TraceLaneSession {
|
|
|
70
68
|
createRecorderForCurrentTest(browser) {
|
|
71
69
|
const recorderOptions = {
|
|
72
70
|
executor: createWdioExecutor(browser),
|
|
73
|
-
rrwebBundle: loadRrwebBundle(),
|
|
71
|
+
rrwebBundle: loadRrwebBundle(import.meta.url),
|
|
74
72
|
};
|
|
75
73
|
if (this.options.drainIntervalMs !== undefined) {
|
|
76
74
|
recorderOptions.drainIntervalMs = this.options.drainIntervalMs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracelane-session.js","sourceRoot":"","sources":["../src/tracelane-session.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,mEAAmE;AACnE,+EAA+E;AAC/E,8EAA8E;AAC9E,2EAA2E;AAC3E,sEAAsE;AAEtE,OAAO,EAIL,
|
|
1
|
+
{"version":3,"file":"tracelane-session.js","sourceRoot":"","sources":["../src/tracelane-session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracelane/wdio",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.17",
|
|
4
4
|
"description": "WebdriverIO Service that records rrweb sessions and writes a self-contained HTML report on failed tests. The user-facing tracelane integration for WDIO.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tracelane",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"README.md"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@tracelane/core": "0.1.0-alpha.
|
|
42
|
-
"@tracelane/report": "0.1.0-alpha.
|
|
41
|
+
"@tracelane/core": "0.1.0-alpha.12",
|
|
42
|
+
"@tracelane/report": "0.1.0-alpha.14"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@wdio/types": "^9.0.0",
|
package/dist/inpage-bundle.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The rrweb in-page bundle source (defines `window.rrweb`). Read from
|
|
3
|
-
* `dist/rrweb-bundle.js`, cached after first read.
|
|
4
|
-
*
|
|
5
|
-
* @throws if the bundle is missing — that means the package was used without its
|
|
6
|
-
* build step (`pnpm --filter @tracelane/wdio build`) having run.
|
|
7
|
-
*/
|
|
8
|
-
export declare function loadRrwebBundle(): string;
|
|
9
|
-
//# sourceMappingURL=inpage-bundle.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inpage-bundle.d.ts","sourceRoot":"","sources":["../src/inpage-bundle.ts"],"names":[],"mappings":"AAgCA;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAWxC"}
|
package/dist/inpage-bundle.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Loads the in-page rrweb bundle source string.
|
|
2
|
-
//
|
|
3
|
-
// The bundle (`dist/rrweb-bundle.js`) is produced at build time by
|
|
4
|
-
// `scripts/build-rrweb-bundle.mjs` (esbuild → IIFE that defines `window.rrweb`
|
|
5
|
-
// with `record` + `getRecordConsolePlugin`). @tracelane/core's recorder is
|
|
6
|
-
// bundle-source-agnostic (ADR-0006) and expects this source as a plain string,
|
|
7
|
-
// which it `window.eval`s in the page on every (re-)injection.
|
|
8
|
-
//
|
|
9
|
-
// We read it once and cache it. In the published package this module compiles
|
|
10
|
-
// to `dist/inpage-bundle.js`, sitting next to `dist/rrweb-bundle.js`; under
|
|
11
|
-
// vitest the source lives in `src/`, so we also probe a sibling `../dist/`. We
|
|
12
|
-
// derive the module directory from `fileURLToPath(import.meta.url)` directly
|
|
13
|
-
// (not via `new URL(rel, import.meta.url)`) because under the jsdom test env the
|
|
14
|
-
// global `URL` resolves relative inputs against the page origin, not the file.
|
|
15
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
-
import { dirname, join } from 'node:path';
|
|
17
|
-
import { fileURLToPath } from 'node:url';
|
|
18
|
-
let cached;
|
|
19
|
-
/** Candidate locations for the built bundle, in priority order. */
|
|
20
|
-
function candidatePaths() {
|
|
21
|
-
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
22
|
-
return [
|
|
23
|
-
// Published layout: dist/inpage-bundle.js → dist/rrweb-bundle.js.
|
|
24
|
-
join(moduleDir, 'rrweb-bundle.js'),
|
|
25
|
-
// Source/test layout: src/inpage-bundle.ts → ../dist/rrweb-bundle.js.
|
|
26
|
-
join(moduleDir, '..', 'dist', 'rrweb-bundle.js'),
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* The rrweb in-page bundle source (defines `window.rrweb`). Read from
|
|
31
|
-
* `dist/rrweb-bundle.js`, cached after first read.
|
|
32
|
-
*
|
|
33
|
-
* @throws if the bundle is missing — that means the package was used without its
|
|
34
|
-
* build step (`pnpm --filter @tracelane/wdio build`) having run.
|
|
35
|
-
*/
|
|
36
|
-
export function loadRrwebBundle() {
|
|
37
|
-
if (cached !== undefined)
|
|
38
|
-
return cached;
|
|
39
|
-
const candidates = candidatePaths();
|
|
40
|
-
const found = candidates.find((p) => existsSync(p));
|
|
41
|
-
if (found === undefined) {
|
|
42
|
-
throw new Error(`@tracelane/wdio: in-page rrweb bundle not found (looked in ${candidates.join(', ')}). Run the package build (\`pnpm --filter @tracelane/wdio build\`) to generate it.`);
|
|
43
|
-
}
|
|
44
|
-
cached = readFileSync(found, 'utf8');
|
|
45
|
-
return cached;
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=inpage-bundle.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inpage-bundle.js","sourceRoot":"","sources":["../src/inpage-bundle.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,mEAAmE;AACnE,+EAA+E;AAC/E,2EAA2E;AAC3E,+EAA+E;AAC/E,+DAA+D;AAC/D,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,iFAAiF;AACjF,+EAA+E;AAE/E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAA0B,CAAC;AAE/B,mEAAmE;AACnE,SAAS,cAAc;IACrB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO;QACL,kEAAkE;QAClE,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC;QAClC,sEAAsE;QACtE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACjD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,8DAA8D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,oFAAoF,CACxK,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { BrowserExecutor } from '@tracelane/core';
|
|
2
|
-
/**
|
|
3
|
-
* Page-side logger. Self-contained (no Node closures) so it can be
|
|
4
|
-
* `.toString()`-serialized by `execute` (PRD §A.4). The console plugin captures
|
|
5
|
-
* this `console.error`; the `[tracelane.net]` prefix lets the report's network
|
|
6
|
-
* panel scrape it back out (PRD §E.2).
|
|
7
|
-
*
|
|
8
|
-
* The status is zero-padded to 3 digits so it satisfies panels.ts's
|
|
9
|
-
* `parseNetConsoleLine` regex (`(\d{3})`); `Number('000')` parses back to a
|
|
10
|
-
* genuine `0`, which — paired with the always-present method — panels.ts treats
|
|
11
|
-
* as a true network failure.
|
|
12
|
-
*/
|
|
13
|
-
declare function logNetworkErrorInPage(url: string, status: number, method: string): void;
|
|
14
|
-
/** Pull the request method out of CDP request headers, defaulting to GET. */
|
|
15
|
-
declare function methodOf(headers: Record<string, string> | undefined): string;
|
|
16
|
-
/**
|
|
17
|
-
* Attach CDP network capture to a BrowserExecutor (P1 PRD §E.2).
|
|
18
|
-
*
|
|
19
|
-
* Enables the Network domain and registers subscribers that forward both HTTP
|
|
20
|
-
* error responses (`Network.responseReceived`, `status >= 400`) and no-response
|
|
21
|
-
* failures (`Network.loadingFailed` — CORS/DNS/offline/abort, audit A-6) into
|
|
22
|
-
* `console.error`. Resolves once `Network.enable` has been sent. The
|
|
23
|
-
* subscribers' own `execute` calls are fire-and-forget (their failures must not
|
|
24
|
-
* break the test).
|
|
25
|
-
*
|
|
26
|
-
* To give the methodless `loadingFailed` events a method (required by panels.ts
|
|
27
|
-
* to classify the row as failed), we keep a small `requestId → { method, url }`
|
|
28
|
-
* map populated from `Network.requestWillBeSent`, and evict an entry once it has
|
|
29
|
-
* either succeeded (`responseReceived`) or failed (`loadingFailed`) so the map
|
|
30
|
-
* can't grow unbounded over a long session.
|
|
31
|
-
*/
|
|
32
|
-
export declare function attachNetworkCapture(executor: BrowserExecutor): Promise<void>;
|
|
33
|
-
export declare const __internal: {
|
|
34
|
-
logNetworkErrorInPage: typeof logNetworkErrorInPage;
|
|
35
|
-
methodOf: typeof methodOf;
|
|
36
|
-
};
|
|
37
|
-
export {};
|
|
38
|
-
//# sourceMappingURL=network-capture.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network-capture.d.ts","sourceRoot":"","sources":["../src/network-capture.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAoCvD;;;;;;;;;;GAUG;AACH,iBAAS,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAMhF;AAED,6EAA6E;AAC7E,iBAAS,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,CAKrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAoDnF;AAGD,eAAO,MAAM,UAAU;;;CAAsC,CAAC"}
|
package/dist/network-capture.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// CDP network capture wiring (Task 2.16 / P1 PRD §E.2).
|
|
2
|
-
//
|
|
3
|
-
// Enable the CDP Network domain and route failures into the page's
|
|
4
|
-
// `console.error` via `executor.execute`. Two failure classes are surfaced:
|
|
5
|
-
//
|
|
6
|
-
// 1. `Network.responseReceived` with `status >= 400` — a response arrived
|
|
7
|
-
// but the server reported an HTTP error (4xx/5xx).
|
|
8
|
-
// 2. `Network.loadingFailed` — the request produced NO response at all
|
|
9
|
-
// (CORS failure, DNS/connection failure, offline, abort). CDP's
|
|
10
|
-
// `responseReceived` never fires for these, and the in-page status-0
|
|
11
|
-
// wrapper is off by default, so without this branch a genuine failed
|
|
12
|
-
// request would be invisible (audit A-6). We surface it with an explicit
|
|
13
|
-
// status `000` (= a real 0 once parsed) so it reads as a true failure.
|
|
14
|
-
//
|
|
15
|
-
// The rrweb console plugin (installed by @tracelane/core's recorder) then
|
|
16
|
-
// captures the console line, so failures show up in the report's network panel
|
|
17
|
-
// "for free" — no dedicated network transport in v1.
|
|
18
|
-
//
|
|
19
|
-
// The console line is prefixed `[tracelane.net]` so @tracelane/report's network
|
|
20
|
-
// panel can scrape it back out (NETWORK_CONSOLE_PREFIX in panels.ts). The line
|
|
21
|
-
// ALWAYS carries a METHOD: panels.ts classifies a `status === 0` scrape row as
|
|
22
|
-
// a true failure only when a method is present (its "true error path" rule —
|
|
23
|
-
// see `isTrueErrorPath`), so a methodless `loadingFailed` line would be
|
|
24
|
-
// silently dropped from the panel.
|
|
25
|
-
/** Status sentinel for a request that produced no response (a true 0 once parsed). */
|
|
26
|
-
const NO_RESPONSE_STATUS = 0;
|
|
27
|
-
/**
|
|
28
|
-
* Page-side logger. Self-contained (no Node closures) so it can be
|
|
29
|
-
* `.toString()`-serialized by `execute` (PRD §A.4). The console plugin captures
|
|
30
|
-
* this `console.error`; the `[tracelane.net]` prefix lets the report's network
|
|
31
|
-
* panel scrape it back out (PRD §E.2).
|
|
32
|
-
*
|
|
33
|
-
* The status is zero-padded to 3 digits so it satisfies panels.ts's
|
|
34
|
-
* `parseNetConsoleLine` regex (`(\d{3})`); `Number('000')` parses back to a
|
|
35
|
-
* genuine `0`, which — paired with the always-present method — panels.ts treats
|
|
36
|
-
* as a true network failure.
|
|
37
|
-
*/
|
|
38
|
-
function logNetworkErrorInPage(url, status, method) {
|
|
39
|
-
// Zero-pad to 3 digits without String.padStart so the .toString()-serialized
|
|
40
|
-
// form runs on older in-page engines too.
|
|
41
|
-
let code = String(status);
|
|
42
|
-
while (code.length < 3)
|
|
43
|
-
code = `0${code}`;
|
|
44
|
-
console.error(`[tracelane.net] ${method} ${code} ${url}`);
|
|
45
|
-
}
|
|
46
|
-
/** Pull the request method out of CDP request headers, defaulting to GET. */
|
|
47
|
-
function methodOf(headers) {
|
|
48
|
-
if (!headers)
|
|
49
|
-
return 'GET';
|
|
50
|
-
// CDP exposes the pseudo-header `:method` for HTTP/2/3; fall back to a plain
|
|
51
|
-
// `method` header, then GET.
|
|
52
|
-
return headers[':method'] ?? headers.method ?? 'GET';
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Attach CDP network capture to a BrowserExecutor (P1 PRD §E.2).
|
|
56
|
-
*
|
|
57
|
-
* Enables the Network domain and registers subscribers that forward both HTTP
|
|
58
|
-
* error responses (`Network.responseReceived`, `status >= 400`) and no-response
|
|
59
|
-
* failures (`Network.loadingFailed` — CORS/DNS/offline/abort, audit A-6) into
|
|
60
|
-
* `console.error`. Resolves once `Network.enable` has been sent. The
|
|
61
|
-
* subscribers' own `execute` calls are fire-and-forget (their failures must not
|
|
62
|
-
* break the test).
|
|
63
|
-
*
|
|
64
|
-
* To give the methodless `loadingFailed` events a method (required by panels.ts
|
|
65
|
-
* to classify the row as failed), we keep a small `requestId → { method, url }`
|
|
66
|
-
* map populated from `Network.requestWillBeSent`, and evict an entry once it has
|
|
67
|
-
* either succeeded (`responseReceived`) or failed (`loadingFailed`) so the map
|
|
68
|
-
* can't grow unbounded over a long session.
|
|
69
|
-
*/
|
|
70
|
-
export async function attachNetworkCapture(executor) {
|
|
71
|
-
await executor.cdp('Network', 'enable');
|
|
72
|
-
// Correlation map: a `loadingFailed` carries only a requestId, so remember the
|
|
73
|
-
// method + url from `requestWillBeSent` to reconstruct a method-bearing line.
|
|
74
|
-
const inflight = new Map();
|
|
75
|
-
const emit = (url, status, method) => {
|
|
76
|
-
// Fire-and-forget: a logging failure (e.g. page mid-navigation) must not
|
|
77
|
-
// surface as a test error.
|
|
78
|
-
void executor
|
|
79
|
-
.execute(logNetworkErrorInPage, url, status, method)
|
|
80
|
-
.catch(() => {
|
|
81
|
-
/* page may be navigating; drop this one line */
|
|
82
|
-
});
|
|
83
|
-
};
|
|
84
|
-
executor.on('Network.requestWillBeSent', (params) => {
|
|
85
|
-
const e = params;
|
|
86
|
-
const id = e?.requestId;
|
|
87
|
-
const url = e?.request?.url;
|
|
88
|
-
if (typeof id !== 'string' || typeof url !== 'string')
|
|
89
|
-
return;
|
|
90
|
-
const method = typeof e.request?.method === 'string' ? e.request.method : 'GET';
|
|
91
|
-
inflight.set(id, { method, url });
|
|
92
|
-
});
|
|
93
|
-
executor.on('Network.responseReceived', (params) => {
|
|
94
|
-
const e = params;
|
|
95
|
-
const response = e?.response;
|
|
96
|
-
// A response arrived — this request will not surface via loadingFailed, so
|
|
97
|
-
// drop it from the inflight map regardless of status.
|
|
98
|
-
if (typeof e?.requestId === 'string')
|
|
99
|
-
inflight.delete(e.requestId);
|
|
100
|
-
const status = response?.status;
|
|
101
|
-
if (typeof status !== 'number' || status < 400)
|
|
102
|
-
return;
|
|
103
|
-
const url = response?.url ?? '';
|
|
104
|
-
const method = methodOf(response?.requestHeaders);
|
|
105
|
-
emit(url, status, method);
|
|
106
|
-
});
|
|
107
|
-
executor.on('Network.loadingFailed', (params) => {
|
|
108
|
-
const e = params;
|
|
109
|
-
const id = e?.requestId;
|
|
110
|
-
// Correlate back to the request's method + url; CORS/DNS/offline/abort
|
|
111
|
-
// failures produce NO response, so this is the only place they surface.
|
|
112
|
-
const tracked = typeof id === 'string' ? inflight.get(id) : undefined;
|
|
113
|
-
if (typeof id === 'string')
|
|
114
|
-
inflight.delete(id);
|
|
115
|
-
const url = tracked?.url ?? '';
|
|
116
|
-
// Method is required for panels.ts to treat the status-0 row as a failure;
|
|
117
|
-
// default to GET if the requestWillBeSent was missed (e.g. attach mid-flight).
|
|
118
|
-
const method = tracked?.method ?? 'GET';
|
|
119
|
-
emit(url, NO_RESPONSE_STATUS, method);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
// Exposed for unit tests: the page-side logger + method resolver are pure.
|
|
123
|
-
export const __internal = { logNetworkErrorInPage, methodOf };
|
|
124
|
-
//# sourceMappingURL=network-capture.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network-capture.js","sourceRoot":"","sources":["../src/network-capture.ts"],"names":[],"mappings":"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"}
|
package/dist/report-writer.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { eventWithTime } from '@cubenest/rrweb-core';
|
|
2
|
-
import { type ReportMeta } from '@tracelane/report';
|
|
3
|
-
/** Inputs for {@link writeReport}. */
|
|
4
|
-
export interface WriteReportInput {
|
|
5
|
-
/** Output directory (created if missing). */
|
|
6
|
-
outDir: string;
|
|
7
|
-
/** Worker capability id (e.g. `0-0`); namespaces the filename for parallel safety. */
|
|
8
|
-
cid?: string | undefined;
|
|
9
|
-
/** Captured rrweb event stream. */
|
|
10
|
-
events: eventWithTime[];
|
|
11
|
-
/** Report metadata (spec, title, status, error, browser, ...). */
|
|
12
|
-
meta: ReportMeta;
|
|
13
|
-
/** Render the report's "Generated by tracelane" footer. Default true. */
|
|
14
|
-
footer?: boolean | undefined;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Turn an arbitrary spec path / test title into a filesystem-safe slug:
|
|
18
|
-
* lowercase, non-alphanumerics collapsed to single dashes, trimmed, capped.
|
|
19
|
-
*/
|
|
20
|
-
export declare function slugify(input: string): string;
|
|
21
|
-
/**
|
|
22
|
-
* Build a unique-ish report filename: `<spec>--<title>--<cid>-<ts>.html`. The
|
|
23
|
-
* timestamp + cid keep retries and parallel workers from overwriting each other.
|
|
24
|
-
*/
|
|
25
|
-
export declare function reportFileName(meta: ReportMeta, cid?: string): string;
|
|
26
|
-
/**
|
|
27
|
-
* Slug for the spec segment: take the file's basename (so an absolute path like
|
|
28
|
-
* `/repo/test/login.spec.ts` doesn't bloat the filename), then strip the common
|
|
29
|
-
* test-file suffixes (`.spec.ts`, `.test.mts`, `.e2e.js`, …) so it slugifies to
|
|
30
|
-
* a clean `login`, not `login-spec`.
|
|
31
|
-
*/
|
|
32
|
-
export declare function specSlug(spec: string): string;
|
|
33
|
-
/**
|
|
34
|
-
* Build the report HTML and write it under `outDir`, namespaced by `cid`.
|
|
35
|
-
* Returns the absolute-or-relative path written (as `join` produced it).
|
|
36
|
-
*/
|
|
37
|
-
export declare function writeReport(input: WriteReportInput): string;
|
|
38
|
-
//# sourceMappingURL=report-writer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"report-writer.d.ts","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAEjE,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,mCAAmC;IACnC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,kEAAkE;IAClE,IAAI,EAAE,UAAU,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAS3D"}
|
package/dist/report-writer.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Write a self-contained HTML report to disk (ADR-0005 / ADR-0006).
|
|
2
|
-
//
|
|
3
|
-
// Given the captured event stream + metadata, call @tracelane/report's
|
|
4
|
-
// buildReport to produce the offline HTML string, then write it under `outDir`.
|
|
5
|
-
// Files are namespaced by `cid` (the WDIO worker capability id) so parallel
|
|
6
|
-
// workers (`maxInstances > 1`) never collide (ADR-0006 action item #6).
|
|
7
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import { buildReport } from '@tracelane/report';
|
|
10
|
-
/**
|
|
11
|
-
* Turn an arbitrary spec path / test title into a filesystem-safe slug:
|
|
12
|
-
* lowercase, non-alphanumerics collapsed to single dashes, trimmed, capped.
|
|
13
|
-
*/
|
|
14
|
-
export function slugify(input) {
|
|
15
|
-
const slug = input
|
|
16
|
-
.toLowerCase()
|
|
17
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
18
|
-
.replace(/^-+|-+$/g, '');
|
|
19
|
-
// Cap length so deeply-nested titles don't blow past filesystem name limits.
|
|
20
|
-
return (slug || 'report').slice(0, 120);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Build a unique-ish report filename: `<spec>--<title>--<cid>-<ts>.html`. The
|
|
24
|
-
* timestamp + cid keep retries and parallel workers from overwriting each other.
|
|
25
|
-
*/
|
|
26
|
-
export function reportFileName(meta, cid) {
|
|
27
|
-
const specPart = meta.spec ? specSlug(meta.spec) : 'spec';
|
|
28
|
-
const titlePart = slugify(meta.title);
|
|
29
|
-
const cidPart = cid ? `${slugify(cid)}-` : '';
|
|
30
|
-
return `${specPart}--${titlePart}--${cidPart}${Date.now()}.html`;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Slug for the spec segment: take the file's basename (so an absolute path like
|
|
34
|
-
* `/repo/test/login.spec.ts` doesn't bloat the filename), then strip the common
|
|
35
|
-
* test-file suffixes (`.spec.ts`, `.test.mts`, `.e2e.js`, …) so it slugifies to
|
|
36
|
-
* a clean `login`, not `login-spec`.
|
|
37
|
-
*/
|
|
38
|
-
export function specSlug(spec) {
|
|
39
|
-
const base = spec.replace(/^.*[/\\]/, '');
|
|
40
|
-
return slugify(base.replace(/(\.(spec|test|e2e|cy))?\.[cm]?[jt]sx?$/, ''));
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Build the report HTML and write it under `outDir`, namespaced by `cid`.
|
|
44
|
-
* Returns the absolute-or-relative path written (as `join` produced it).
|
|
45
|
-
*/
|
|
46
|
-
export function writeReport(input) {
|
|
47
|
-
const { outDir, cid, events, meta, footer } = input;
|
|
48
|
-
const html = buildReport(events, meta, footer === false ? { footer: false } : {});
|
|
49
|
-
if (!existsSync(outDir)) {
|
|
50
|
-
mkdirSync(outDir, { recursive: true });
|
|
51
|
-
}
|
|
52
|
-
const filePath = join(outDir, reportFileName(meta, cid));
|
|
53
|
-
writeFileSync(filePath, html);
|
|
54
|
-
return filePath;
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=report-writer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"report-writer.js","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,gFAAgF;AAChF,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAmB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAgBjE;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,IAAI,GAAG,KAAK;SACf,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,6EAA6E;IAC7E,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,GAAY;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO,GAAG,QAAQ,KAAK,SAAS,KAAK,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,wCAAwC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACpD,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClF,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IACzD,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC9B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|