@tracelane/report 0.1.0-alpha.2 → 0.1.0-alpha.20
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/NOTICE +8 -0
- package/README.md +33 -5
- package/dist/_security/detectors/insecure-cookies.d.ts +4 -0
- package/dist/_security/detectors/insecure-cookies.d.ts.map +1 -0
- package/dist/_security/detectors/insecure-cookies.js +32 -0
- package/dist/_security/detectors/insecure-cookies.js.map +1 -0
- package/dist/_security/detectors/missing-headers.d.ts +4 -0
- package/dist/_security/detectors/missing-headers.d.ts.map +1 -0
- package/dist/_security/detectors/missing-headers.js +36 -0
- package/dist/_security/detectors/missing-headers.js.map +1 -0
- package/dist/_security/detectors/mixed-content.d.ts +5 -0
- package/dist/_security/detectors/mixed-content.d.ts.map +1 -0
- package/dist/_security/detectors/mixed-content.js +74 -0
- package/dist/_security/detectors/mixed-content.js.map +1 -0
- package/dist/_security/detectors/reverse-tabnabbing.d.ts +10 -0
- package/dist/_security/detectors/reverse-tabnabbing.d.ts.map +1 -0
- package/dist/_security/detectors/reverse-tabnabbing.js +44 -0
- package/dist/_security/detectors/reverse-tabnabbing.js.map +1 -0
- package/dist/_security/index.d.ts +29 -0
- package/dist/_security/index.d.ts.map +1 -0
- package/dist/_security/index.js +36 -0
- package/dist/_security/index.js.map +1 -0
- package/dist/_security/response-meta.d.ts +28 -0
- package/dist/_security/response-meta.d.ts.map +1 -0
- package/dist/_security/response-meta.js +50 -0
- package/dist/_security/response-meta.js.map +1 -0
- package/dist/_security/serialized-dom.d.ts +20 -0
- package/dist/_security/serialized-dom.d.ts.map +1 -0
- package/dist/_security/serialized-dom.js +32 -0
- package/dist/_security/serialized-dom.js.map +1 -0
- package/dist/_security/suppress.d.ts +7 -0
- package/dist/_security/suppress.d.ts.map +1 -0
- package/dist/_security/suppress.js +8 -0
- package/dist/_security/suppress.js.map +1 -0
- package/dist/assets.d.ts +20 -0
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +60 -6
- package/dist/assets.js.map +1 -1
- package/dist/build-report.d.ts +19 -0
- package/dist/build-report.d.ts.map +1 -1
- package/dist/build-report.js +20 -2
- package/dist/build-report.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +2 -1
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +11 -1
- package/dist/markdown.js.map +1 -1
- package/dist/metadata.d.ts +21 -2
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +98 -27
- package/dist/metadata.js.map +1 -1
- package/dist/panels.d.ts +40 -5
- package/dist/panels.d.ts.map +1 -1
- package/dist/panels.js +175 -23
- package/dist/panels.js.map +1 -1
- package/dist/report-writer.d.ts +43 -0
- package/dist/report-writer.d.ts.map +1 -0
- package/dist/report-writer.js +65 -0
- package/dist/report-writer.js.map +1 -0
- package/dist/template.d.ts +19 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +987 -72
- package/dist/template.js.map +1 -1
- package/package.json +28 -7
package/dist/panels.js
CHANGED
|
@@ -5,18 +5,39 @@
|
|
|
5
5
|
// renders them — no event filtering happens in the browser). Extracting at
|
|
6
6
|
// build time keeps all the parsing logic unit-testable and the runtime thin.
|
|
7
7
|
//
|
|
8
|
-
// Sources (P1 PRD §F.3 / §E.2):
|
|
8
|
+
// Sources (P1 PRD §F.3 / §E.2 + Phase 5 network-plugin integration):
|
|
9
9
|
// • Console — EventType.Plugin (6) with data.plugin === 'rrweb/console@1'.
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
10
|
+
// The CDP network-scrape lines ('[tracelane.net] …') are filtered OUT of
|
|
11
|
+
// the console panel (they're a network signal, surfaced as Network rows).
|
|
12
|
+
// • Network — UNION of the framework-agnostic in-page plugin
|
|
13
|
+
// (EventType.Plugin (6), data.plugin === 'rrweb/network@1'; ships in
|
|
14
|
+
// `@cubenest/rrweb-core`) and the v1 CDP console-scrape
|
|
15
|
+
// ('[tracelane.net]'), where the CDP row's AUTHORITATIVE status wins for
|
|
16
|
+
// an overlapping request. Falls back to the v1.1 EventType.Custom (5)
|
|
17
|
+
// path (tag 'tracelane.test.network-error') for pre-Phase-5 recorders
|
|
18
|
+
// that emitted neither source.
|
|
19
|
+
import { EventType, NETWORK_PLUGIN_NAME } from '@cubenest/rrweb-core';
|
|
14
20
|
/** rrweb console plugin tag (P1 PRD §F.3). */
|
|
15
21
|
export const CONSOLE_PLUGIN = 'rrweb/console@1';
|
|
22
|
+
/**
|
|
23
|
+
* rrweb network plugin tag — the framework-agnostic in-page capture
|
|
24
|
+
* (`rrweb/network@1`). Re-exported from `@cubenest/rrweb-core` so it stays
|
|
25
|
+
* in sync with the substrate's wire-format contract.
|
|
26
|
+
*/
|
|
27
|
+
export const NETWORK_PLUGIN = NETWORK_PLUGIN_NAME;
|
|
16
28
|
/** Custom-event tag for the v1.1 rich network path (P1 PRD §E.3). */
|
|
17
29
|
export const NETWORK_EVENT_TAG = 'tracelane.test.network-error';
|
|
18
30
|
/** console.error prefix for the v1 network fallback (P1 PRD §E.2). */
|
|
19
31
|
export const NETWORK_CONSOLE_PREFIX = '[tracelane.net]';
|
|
32
|
+
/**
|
|
33
|
+
* console.error prefix the capture layer uses for privacy-safe response
|
|
34
|
+
* metadata consumed by `@tracelane/security`. Like the network-scrape lines,
|
|
35
|
+
* these are a non-console signal and are filtered OUT of the console panel —
|
|
36
|
+
* the security analyzer surfaces them as advisory findings instead. Defined
|
|
37
|
+
* locally (mirroring {@link NETWORK_CONSOLE_PREFIX}) rather than imported from
|
|
38
|
+
* `@tracelane/security` just for a string constant.
|
|
39
|
+
*/
|
|
40
|
+
export const SEC_CONSOLE_PREFIX = '[tracelane.sec]';
|
|
20
41
|
function isPlugin(e) {
|
|
21
42
|
return e.type === EventType.Plugin;
|
|
22
43
|
}
|
|
@@ -56,10 +77,13 @@ function safeStringify(value) {
|
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
/**
|
|
59
|
-
*
|
|
60
|
-
* plugin. The plugin nests the level + serialized args under
|
|
80
|
+
* All console-plugin rows, UNFILTERED — EventType.Plugin events emitted by the
|
|
81
|
+
* rrweb console plugin. The plugin nests the level + serialized args under
|
|
82
|
+
* `data.payload`. This includes the CDP network-scrape lines
|
|
83
|
+
* ('[tracelane.net] …'); `extractNetwork` reads those here to recover the
|
|
84
|
+
* authoritative status, while `extractConsole` filters them out for its panel.
|
|
61
85
|
*/
|
|
62
|
-
|
|
86
|
+
function extractConsoleRows(events) {
|
|
63
87
|
const rows = [];
|
|
64
88
|
for (const e of events) {
|
|
65
89
|
if (!isPlugin(e))
|
|
@@ -67,12 +91,25 @@ export function extractConsole(events) {
|
|
|
67
91
|
const data = e.data;
|
|
68
92
|
if (data.plugin !== CONSOLE_PLUGIN)
|
|
69
93
|
continue;
|
|
70
|
-
const
|
|
71
|
-
const
|
|
94
|
+
const payload = data.payload;
|
|
95
|
+
const level = typeof payload?.level === 'string' ? payload.level : 'log';
|
|
96
|
+
const message = stringifyArgs(payload?.payload);
|
|
72
97
|
rows.push({ level, message, timestamp: e.timestamp });
|
|
73
98
|
}
|
|
74
99
|
return rows;
|
|
75
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Extract console panel rows. Drops the CDP network-scrape lines
|
|
103
|
+
* ('[tracelane.net] …'): they are a *network* signal that `extractNetwork`
|
|
104
|
+
* already surfaces as structured rows in the Network panel. Letting them
|
|
105
|
+
* through here double-renders the same failure as a raw console string,
|
|
106
|
+
* inconsistently with the structured row (audit A-4). Also drops the
|
|
107
|
+
* '[tracelane.sec] …' response-metadata lines: those are a *security* signal
|
|
108
|
+
* the analyzer turns into advisory findings, not console output (Task 9).
|
|
109
|
+
*/
|
|
110
|
+
export function extractConsole(events) {
|
|
111
|
+
return extractConsoleRows(events).filter((row) => !row.message.includes(NETWORK_CONSOLE_PREFIX) && !row.message.includes(SEC_CONSOLE_PREFIX));
|
|
112
|
+
}
|
|
76
113
|
/** Parse a '[tracelane.net] <METHOD> <STATUS> <URL>' console line, if it is one. */
|
|
77
114
|
function parseNetConsoleLine(message, timestamp) {
|
|
78
115
|
const idx = message.indexOf(NETWORK_CONSOLE_PREFIX);
|
|
@@ -91,11 +128,135 @@ function parseNetConsoleLine(message, timestamp) {
|
|
|
91
128
|
};
|
|
92
129
|
}
|
|
93
130
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
131
|
+
* initiatorTypes that come from a true fetch/XHR error path. The plugin tags
|
|
132
|
+
* fetch/XHR wrapper rows with exactly these; everything else (img/script/link/
|
|
133
|
+
* css/font/navigation/…) is a PerformanceObserver timing entry.
|
|
134
|
+
*/
|
|
135
|
+
const ERROR_PATH_INITIATORS = new Set(['fetch', 'xmlhttprequest']);
|
|
136
|
+
/**
|
|
137
|
+
* Whether a `status === 0` request came from a *true* error path rather than
|
|
138
|
+
* a PerformanceObserver timing entry (audit A-1).
|
|
139
|
+
*
|
|
140
|
+
* The in-page `rrweb/network@1` plugin's default mode is PerformanceObserver:
|
|
141
|
+
* successful cross-origin SUB-resources (img/script/link/css/font — analytics,
|
|
142
|
+
* CDN, Google Fonts) report `responseStatus: 0` per the Resource Timing spec
|
|
143
|
+
* **even though they loaded with HTTP 200**. Treating those as failures
|
|
144
|
+
* surfaces PHANTOM network errors. Only the fetch/XHR wrappers (and CDP rows)
|
|
145
|
+
* report a real status, so a status-0 there is a genuine network error.
|
|
146
|
+
*
|
|
147
|
+
* Discriminator: an error-path row has `initiatorType` of `'fetch'` /
|
|
148
|
+
* `'xmlhttprequest'` (and typically a `method`); a PerformanceObserver
|
|
149
|
+
* sub-resource has a resource-type `initiatorType` (img/script/css/…) and no
|
|
150
|
+
* `method`. We require either an explicit fetch/XHR initiatorType OR (no
|
|
151
|
+
* initiatorType at all AND a `method`) — the latter covers older substrates
|
|
152
|
+
* that omitted initiatorType on the wrapper rows.
|
|
153
|
+
*/
|
|
154
|
+
function isTrueErrorPath(req) {
|
|
155
|
+
const initiator = typeof req.initiatorType === 'string' ? req.initiatorType : undefined;
|
|
156
|
+
if (initiator !== undefined)
|
|
157
|
+
return ERROR_PATH_INITIATORS.has(initiator);
|
|
158
|
+
// No initiatorType: a `method` indicates a fetch/XHR wrapper row (a true
|
|
159
|
+
// request), whereas a PerformanceObserver entry never carries a method.
|
|
160
|
+
return typeof req.method === 'string';
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Coerce a `CapturedNetworkRequest` from the network plugin into a
|
|
164
|
+
* panel-visible `NetworkEntry`. Treats genuine network errors (`status === 0`
|
|
165
|
+
* on a true fetch/XHR error path) and 4xx/5xx responses as "failed" — matches
|
|
166
|
+
* the report's existing "Network errors" panel semantics. Returns `undefined`
|
|
167
|
+
* for non-failed requests so the caller can skip them.
|
|
168
|
+
*
|
|
169
|
+
* A `status === 0` PerformanceObserver sub-resource is NOT a failure (see
|
|
170
|
+
* {@link isTrueErrorPath}) — those are cross-origin resources that loaded fine
|
|
171
|
+
* but report 0 per the Resource Timing spec.
|
|
172
|
+
*
|
|
173
|
+
* `fallbackTs` is the wrapping rrweb event's `timestamp` (wall-clock ms);
|
|
174
|
+
* we prefer the captured request's `timestamp` field when present (also
|
|
175
|
+
* wall-clock ms — `timeOrigin + requestMadeAt` in the plugin), and fall
|
|
176
|
+
* back to the wrapping event's timestamp so panel ordering still works
|
|
177
|
+
* when the plugin omits per-request `timestamp` (e.g. older substrates).
|
|
178
|
+
*/
|
|
179
|
+
function networkEntryFromCapturedRequest(req, fallbackTs) {
|
|
180
|
+
const status = typeof req.status === 'number' ? req.status : undefined;
|
|
181
|
+
// Filter to FAILED requests only — the renderer's panel is "Network errors"
|
|
182
|
+
// and the v1/v1.1 paths only ever surfaced failures. Successful 2xx/3xx
|
|
183
|
+
// responses captured by the plugin's broader PerformanceObserver path are
|
|
184
|
+
// intentionally dropped here. A status of 0 only counts as a failure when it
|
|
185
|
+
// came from a true error path (fetch/XHR), never a PerformanceObserver
|
|
186
|
+
// sub-resource that reports 0 per the Resource Timing spec (audit A-1).
|
|
187
|
+
const isFailed = (status === 0 && isTrueErrorPath(req)) || (status !== undefined && status >= 400);
|
|
188
|
+
if (!isFailed)
|
|
189
|
+
return undefined;
|
|
190
|
+
const ts = typeof req.timestamp === 'number' ? req.timestamp : fallbackTs;
|
|
191
|
+
const url = typeof req.name === 'string' ? req.name : '';
|
|
192
|
+
return {
|
|
193
|
+
...(typeof req.method === 'string' ? { method: req.method } : {}),
|
|
194
|
+
url,
|
|
195
|
+
status: status ?? 0,
|
|
196
|
+
timestamp: ts,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/** Normalize a URL for cross-source dedup (drop trailing slash + fragment). */
|
|
200
|
+
function networkKey(url) {
|
|
201
|
+
return url.replace(/#.*$/, '').replace(/\/$/, '');
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Extract network-error rows.
|
|
205
|
+
*
|
|
206
|
+
* The in-page rrweb network plugin (`rrweb/network@1`, the Phase 5 default)
|
|
207
|
+
* captures via PerformanceObserver, so its rows are status-poor for
|
|
208
|
+
* cross-origin requests. The legacy CDP `[tracelane.net]` console-scrape, when
|
|
209
|
+
* present, carries the AUTHORITATIVE HTTP status. So rather than "first
|
|
210
|
+
* non-empty source wins" — which would shadow the authoritative CDP rows
|
|
211
|
+
* whenever the plugin emitted anything (audit A-4) — we UNION the plugin + CDP
|
|
212
|
+
* sources, with CDP rows replacing an overlapping plugin row for the same URL.
|
|
213
|
+
*
|
|
214
|
+
* Resolution:
|
|
215
|
+
* 1. Failed rows from the in-page network plugin (EventType.Plugin) merged
|
|
216
|
+
* with the v1 CDP console-scrape ('[tracelane.net]'), where a CDP row
|
|
217
|
+
* REPLACES an overlapping plugin row for the same request (real status
|
|
218
|
+
* wins over a PerformanceObserver 0). Output ordered by timestamp.
|
|
219
|
+
* 2. If neither produced any rows, fall back to the v1.1 custom-event path
|
|
220
|
+
* (EventType.Custom) — pre-Phase-5 recorders that used neither the plugin
|
|
221
|
+
* nor the CDP console-scrape.
|
|
97
222
|
*/
|
|
98
223
|
export function extractNetwork(events) {
|
|
224
|
+
// 1a. The in-page network plugin (framework-agnostic; PerformanceObserver).
|
|
225
|
+
const fromPlugin = [];
|
|
226
|
+
for (const e of events) {
|
|
227
|
+
if (!isPlugin(e))
|
|
228
|
+
continue;
|
|
229
|
+
const data = e.data;
|
|
230
|
+
if (data.plugin !== NETWORK_PLUGIN)
|
|
231
|
+
continue;
|
|
232
|
+
const payload = data.payload;
|
|
233
|
+
if (!payload || !Array.isArray(payload.requests))
|
|
234
|
+
continue;
|
|
235
|
+
for (const req of payload.requests) {
|
|
236
|
+
const entry = networkEntryFromCapturedRequest(req, e.timestamp);
|
|
237
|
+
if (entry)
|
|
238
|
+
fromPlugin.push(entry);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// 1b. v1 CDP console-scrape — AUTHORITATIVE status. Read the unfiltered
|
|
242
|
+
// console rows here (extractConsole() drops these lines for its panel).
|
|
243
|
+
const scraped = [];
|
|
244
|
+
for (const row of extractConsoleRows(events)) {
|
|
245
|
+
const parsed = parseNetConsoleLine(row.message, row.timestamp);
|
|
246
|
+
if (parsed)
|
|
247
|
+
scraped.push(parsed);
|
|
248
|
+
}
|
|
249
|
+
if (fromPlugin.length > 0 || scraped.length > 0) {
|
|
250
|
+
// Merge: CDP rows are authoritative and replace an overlapping plugin row
|
|
251
|
+
// for the same URL; everything non-overlapping from both is retained.
|
|
252
|
+
const byKey = new Map();
|
|
253
|
+
for (const entry of fromPlugin)
|
|
254
|
+
byKey.set(networkKey(entry.url), entry);
|
|
255
|
+
for (const entry of scraped)
|
|
256
|
+
byKey.set(networkKey(entry.url), entry);
|
|
257
|
+
return [...byKey.values()].sort((a, b) => a.timestamp - b.timestamp);
|
|
258
|
+
}
|
|
259
|
+
// 2. v1.1 fallback: rich custom events (pre-Phase-5 recorders).
|
|
99
260
|
const rich = [];
|
|
100
261
|
for (const e of events) {
|
|
101
262
|
if (!isCustom(e))
|
|
@@ -111,15 +272,6 @@ export function extractNetwork(events) {
|
|
|
111
272
|
timestamp: e.timestamp,
|
|
112
273
|
});
|
|
113
274
|
}
|
|
114
|
-
|
|
115
|
-
return rich;
|
|
116
|
-
// v1 fallback: scrape the console.
|
|
117
|
-
const scraped = [];
|
|
118
|
-
for (const row of extractConsole(events)) {
|
|
119
|
-
const parsed = parseNetConsoleLine(row.message, row.timestamp);
|
|
120
|
-
if (parsed)
|
|
121
|
-
scraped.push(parsed);
|
|
122
|
-
}
|
|
123
|
-
return scraped;
|
|
275
|
+
return rich;
|
|
124
276
|
}
|
|
125
277
|
//# sourceMappingURL=panels.js.map
|
package/dist/panels.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panels.js","sourceRoot":"","sources":["../src/panels.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"panels.js","sourceRoot":"","sources":["../src/panels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { eventWithTime } from '@cubenest/rrweb-core';
|
|
2
|
+
import type { Suppression } from './_security/index.js';
|
|
3
|
+
import type { ReportMeta } from './types.js';
|
|
4
|
+
/** Inputs for {@link writeReport}. */
|
|
5
|
+
export interface WriteReportInput {
|
|
6
|
+
/** Output directory (created if missing). */
|
|
7
|
+
outDir: string;
|
|
8
|
+
/** Worker/project id (e.g. WDIO `0-0` or a Playwright project name); namespaces the filename for parallel safety. */
|
|
9
|
+
cid?: string | undefined;
|
|
10
|
+
/** Captured rrweb event stream. */
|
|
11
|
+
events: eventWithTime[];
|
|
12
|
+
/** Report metadata (spec, title, status, error, browser, ...). */
|
|
13
|
+
meta: ReportMeta;
|
|
14
|
+
/** Render the report's "Generated by tracelane" footer. Default true. */
|
|
15
|
+
footer?: boolean | undefined;
|
|
16
|
+
/** Run the advisory security analyzer + render its findings. Default true. */
|
|
17
|
+
security?: boolean | undefined;
|
|
18
|
+
/** Suppressions forwarded to the analyzer. Ignored when `security` is false. */
|
|
19
|
+
securitySuppress?: Suppression[] | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Turn an arbitrary spec path / test title into a filesystem-safe slug:
|
|
23
|
+
* lowercase, non-alphanumerics collapsed to single dashes, trimmed, capped.
|
|
24
|
+
*/
|
|
25
|
+
export declare function slugify(input: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Build a unique-ish report filename: `<spec>--<title>--<cid>-<ts>.html`. The
|
|
28
|
+
* timestamp + cid keep retries and parallel workers from overwriting each other.
|
|
29
|
+
*/
|
|
30
|
+
export declare function reportFileName(meta: ReportMeta, cid?: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Slug for the spec segment: take the file's basename (so an absolute path like
|
|
33
|
+
* `/repo/test/login.spec.ts` doesn't bloat the filename), then strip the common
|
|
34
|
+
* test-file suffixes (`.spec.ts`, `.test.mts`, `.e2e.js`, …) so it slugifies to
|
|
35
|
+
* a clean `login`, not `login-spec`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function specSlug(spec: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build the report HTML and write it under `outDir`, namespaced by `cid`.
|
|
40
|
+
* Returns the absolute-or-relative path written (as `join` produced it).
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeReport(input: WriteReportInput): string;
|
|
43
|
+
//# sourceMappingURL=report-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-writer.d.ts","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,qHAAqH;IACrH,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;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;CAC9C;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,CAa3D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Write a self-contained HTML report to disk (ADR-0005 / ADR-0006).
|
|
2
|
+
//
|
|
3
|
+
// Given the captured event stream + metadata, call buildReport to produce the
|
|
4
|
+
// offline HTML string, then write it under `outDir`. Files are namespaced by
|
|
5
|
+
// `cid` (the adapter's worker/project id — e.g. the WDIO capability id or the
|
|
6
|
+
// Playwright project name) so parallel workers never collide (ADR-0006 action
|
|
7
|
+
// item #6). Lives in @tracelane/report so every adapter (WDIO, Playwright)
|
|
8
|
+
// shares one write path.
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { buildReport } from './build-report.js';
|
|
12
|
+
/**
|
|
13
|
+
* Turn an arbitrary spec path / test title into a filesystem-safe slug:
|
|
14
|
+
* lowercase, non-alphanumerics collapsed to single dashes, trimmed, capped.
|
|
15
|
+
*/
|
|
16
|
+
export function slugify(input) {
|
|
17
|
+
const slug = input
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
20
|
+
.replace(/^-+|-+$/g, '');
|
|
21
|
+
// Cap length so deeply-nested titles don't blow past filesystem name limits.
|
|
22
|
+
return (slug || 'report').slice(0, 120);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build a unique-ish report filename: `<spec>--<title>--<cid>-<ts>.html`. The
|
|
26
|
+
* timestamp + cid keep retries and parallel workers from overwriting each other.
|
|
27
|
+
*/
|
|
28
|
+
export function reportFileName(meta, cid) {
|
|
29
|
+
const specPart = meta.spec ? specSlug(meta.spec) : 'spec';
|
|
30
|
+
const titlePart = slugify(meta.title);
|
|
31
|
+
const cidPart = cid ? `${slugify(cid)}-` : '';
|
|
32
|
+
return `${specPart}--${titlePart}--${cidPart}${Date.now()}.html`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Slug for the spec segment: take the file's basename (so an absolute path like
|
|
36
|
+
* `/repo/test/login.spec.ts` doesn't bloat the filename), then strip the common
|
|
37
|
+
* test-file suffixes (`.spec.ts`, `.test.mts`, `.e2e.js`, …) so it slugifies to
|
|
38
|
+
* a clean `login`, not `login-spec`.
|
|
39
|
+
*/
|
|
40
|
+
export function specSlug(spec) {
|
|
41
|
+
const base = spec.replace(/^.*[/\\]/, '');
|
|
42
|
+
return slugify(base.replace(/(\.(spec|test|e2e|cy))?\.[cm]?[jt]sx?$/, ''));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the report HTML and write it under `outDir`, namespaced by `cid`.
|
|
46
|
+
* Returns the absolute-or-relative path written (as `join` produced it).
|
|
47
|
+
*/
|
|
48
|
+
export function writeReport(input) {
|
|
49
|
+
const { outDir, cid, events, meta, footer, security, securitySuppress } = input;
|
|
50
|
+
const buildOptions = {};
|
|
51
|
+
if (footer === false)
|
|
52
|
+
buildOptions.footer = false;
|
|
53
|
+
if (security !== undefined)
|
|
54
|
+
buildOptions.security = security;
|
|
55
|
+
if (securitySuppress !== undefined)
|
|
56
|
+
buildOptions.securitySuppress = securitySuppress;
|
|
57
|
+
const html = buildReport(events, meta, buildOptions);
|
|
58
|
+
if (!existsSync(outDir)) {
|
|
59
|
+
mkdirSync(outDir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
const filePath = join(outDir, reportFileName(meta, cid));
|
|
62
|
+
writeFileSync(filePath, html);
|
|
63
|
+
return filePath;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=report-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-writer.js","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,yBAAyB;AAEzB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAA2B,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqBzE;;;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,QAAQ,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;IAChF,MAAM,YAAY,GAAuB,EAAE,CAAC;IAC5C,IAAI,MAAM,KAAK,KAAK;QAAE,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC;IAClD,IAAI,QAAQ,KAAK,SAAS;QAAE,YAAY,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7D,IAAI,gBAAgB,KAAK,SAAS;QAAE,YAAY,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IACrF,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IACrD,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"}
|
package/dist/template.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SecurityFinding } from './_security/index.js';
|
|
1
2
|
import type { ConsoleEntry, NetworkEntry } from './panels.js';
|
|
2
3
|
import type { ReportMeta } from './types.js';
|
|
3
4
|
/** Everything `renderReportHtml` needs; build-report.ts prepares it. */
|
|
@@ -9,10 +10,28 @@ export interface ReportTemplateData {
|
|
|
9
10
|
console: ConsoleEntry[];
|
|
10
11
|
/** Extracted network panel rows (Task 2.10). */
|
|
11
12
|
network: NetworkEntry[];
|
|
13
|
+
/**
|
|
14
|
+
* Advisory security-hygiene findings (Task 12). Rendered as a collapsed
|
|
15
|
+
* panel; the panel + its tab are OMITTED entirely when this is empty (no
|
|
16
|
+
* zero-state). Advisory only — NOT a security audit.
|
|
17
|
+
*/
|
|
18
|
+
security: SecurityFinding[];
|
|
12
19
|
/** Pre-rendered "Copy as Markdown for AI paste" payload (Task 2.12). */
|
|
13
20
|
markdown: string;
|
|
14
21
|
/** Whether the events were pruned to fit the size budget (ADR-0005 banner). */
|
|
15
22
|
pruned: boolean;
|
|
23
|
+
/** Total recorded event count (Phase 6 meta-strip). */
|
|
24
|
+
eventCount: number;
|
|
25
|
+
/** Earliest event timestamp (wall-clock ms) or 0 if no events. */
|
|
26
|
+
firstTs: number;
|
|
27
|
+
/** Latest event timestamp (wall-clock ms) or 0 if no events. Treated as the
|
|
28
|
+
* "failure" moment for the timeline marker when the test failed. */
|
|
29
|
+
lastTs: number;
|
|
30
|
+
/**
|
|
31
|
+
* Render the self-marketing footer. Default true. Pass false to suppress it
|
|
32
|
+
* (`report: { footer: false }` opt-out — audit A-8).
|
|
33
|
+
*/
|
|
34
|
+
footer?: boolean;
|
|
16
35
|
}
|
|
17
36
|
/** Compose the full self-contained HTML document. */
|
|
18
37
|
export declare function renderReportHtml(data: ReportTemplateData): string;
|
package/dist/template.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAW5D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;;;OAIG;IACH,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB;yEACqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA86BD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAqJjE"}
|