@piwitests/reporter 0.5.0 → 0.6.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.
- package/README.md +37 -26
- package/dist/global-setup-module.js +2 -2
- package/dist/index.d.ts +13 -4
- package/dist/index.js +19 -5
- package/dist/internal/capture/attachments.d.ts +19 -0
- package/dist/internal/capture/attachments.js +22 -0
- package/dist/{fixtures.d.ts → internal/capture/capture-fixtures.d.ts} +5 -3
- package/dist/internal/capture/capture-fixtures.js +495 -0
- package/dist/{locator-healing.js → internal/capture/locator-healing.js} +11 -6
- package/dist/internal/collect/error-text.d.ts +18 -0
- package/dist/internal/collect/error-text.js +79 -0
- package/dist/{metadata-collector.d.ts → internal/collect/metadata-collector.d.ts} +2 -2
- package/dist/{metadata-collector.js → internal/collect/metadata-collector.js} +12 -9
- package/dist/{skip-classify.d.ts → internal/collect/skip-classify.d.ts} +1 -1
- package/dist/{step-analyzer.d.ts → internal/collect/step-analyzer.d.ts} +6 -0
- package/dist/{step-analyzer.js → internal/collect/step-analyzer.js} +7 -2
- package/dist/internal/config/env.d.ts +45 -0
- package/dist/{config.js → internal/config/env.js} +50 -35
- package/dist/internal/files/compression.js +69 -0
- package/dist/{file-handler.d.ts → internal/files/file-handler.d.ts} +4 -4
- package/dist/{file-handler.js → internal/files/file-handler.js} +61 -29
- package/dist/{crash-recovery.d.ts → internal/streaming/crash-recovery.d.ts} +5 -5
- package/dist/{crash-recovery.js → internal/streaming/crash-recovery.js} +9 -8
- package/dist/{stream-buffer.d.ts → internal/streaming/stream-buffer.d.ts} +2 -2
- package/dist/{stream-buffer.js → internal/streaming/stream-buffer.js} +5 -5
- package/dist/{stream-manager.d.ts → internal/streaming/stream-manager.d.ts} +8 -8
- package/dist/{stream-manager.js → internal/streaming/stream-manager.js} +16 -13
- package/dist/{run-submitter.d.ts → internal/submit/run-submitter.d.ts} +7 -7
- package/dist/{run-submitter.js → internal/submit/run-submitter.js} +11 -9
- package/dist/{serializer.d.ts → internal/submit/serializer.d.ts} +1 -1
- package/dist/{uploader.d.ts → internal/submit/uploader.d.ts} +8 -8
- package/dist/{uploader.js → internal/submit/uploader.js} +45 -10
- package/dist/internal/support/ci.d.ts +2 -0
- package/dist/internal/support/ci.js +32 -0
- package/dist/internal/support/cli-filters.d.ts +1 -0
- package/dist/internal/support/cli-filters.js +51 -0
- package/dist/internal/support/errors.d.ts +8 -0
- package/dist/internal/support/errors.js +15 -0
- package/dist/internal/support/instance-id.d.ts +4 -0
- package/dist/internal/support/instance-id.js +48 -0
- package/dist/internal/support/limiter.d.ts +2 -0
- package/dist/internal/support/limiter.js +27 -0
- package/dist/internal/support/setup-file.d.ts +13 -0
- package/dist/internal/support/setup-file.js +61 -0
- package/dist/internal/support/source-snippet.d.ts +12 -0
- package/dist/internal/support/source-snippet.js +97 -0
- package/dist/internal/support/worker-index.d.ts +7 -0
- package/dist/internal/support/worker-index.js +14 -0
- package/dist/{http-client.d.ts → internal/transport/http-client.d.ts} +11 -1
- package/dist/{http-client.js → internal/transport/http-client.js} +57 -10
- package/dist/{config-wrapper.d.ts → public/config-wrapper.d.ts} +1 -1
- package/dist/{config-wrapper.js → public/config-wrapper.js} +4 -4
- package/dist/public/global-setup.d.ts +13 -0
- package/dist/public/global-setup.js +146 -0
- package/dist/{config.d.ts → public/options.d.ts} +7 -45
- package/dist/public/options.js +2 -0
- package/dist/{reporter.d.ts → public/reporter.d.ts} +1 -1
- package/dist/{reporter.js → public/reporter.js} +44 -54
- package/dist/types/collected.d.ts +96 -0
- package/dist/types/collected.js +10 -0
- package/dist/types/wire.d.ts +174 -0
- package/dist/types/wire.js +14 -0
- package/dist/types.d.ts +8 -253
- package/dist/types.js +23 -10
- package/package.json +1 -6
- package/dist/compression.js +0 -39
- package/dist/fixtures.js +0 -336
- package/dist/helpers.d.ts +0 -44
- package/dist/helpers.js +0 -312
- /package/dist/{locator-healing.d.ts → internal/capture/locator-healing.d.ts} +0 -0
- /package/dist/{skip-classify.js → internal/collect/skip-classify.js} +0 -0
- /package/dist/{compression.d.ts → internal/files/compression.d.ts} +0 -0
- /package/dist/{serializer.js → internal/submit/serializer.js} +0 -0
- /package/dist/{logger.d.ts → internal/support/logger.d.ts} +0 -0
- /package/dist/{logger.js → internal/support/logger.js} +0 -0
|
@@ -34,45 +34,37 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.PiwiDashboardReporter = void 0;
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
39
|
-
const http_client_js_1 = require("
|
|
40
|
-
const uploader_js_1 = require("
|
|
41
|
-
const stream_buffer_js_1 = require("
|
|
42
|
-
const crash_recovery_js_1 = require("
|
|
43
|
-
const file_handler_js_1 = require("
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const env_js_1 = require("../internal/config/env.js");
|
|
39
|
+
const http_client_js_1 = require("../internal/transport/http-client.js");
|
|
40
|
+
const uploader_js_1 = require("../internal/submit/uploader.js");
|
|
41
|
+
const stream_buffer_js_1 = require("../internal/streaming/stream-buffer.js");
|
|
42
|
+
const crash_recovery_js_1 = require("../internal/streaming/crash-recovery.js");
|
|
43
|
+
const file_handler_js_1 = require("../internal/files/file-handler.js");
|
|
44
|
+
const attachments_js_1 = require("../internal/capture/attachments.js");
|
|
45
|
+
const metadata_collector_js_1 = require("../internal/collect/metadata-collector.js");
|
|
46
|
+
const stream_manager_js_1 = require("../internal/streaming/stream-manager.js");
|
|
47
|
+
const step_analyzer_js_1 = require("../internal/collect/step-analyzer.js");
|
|
48
|
+
const instance_id_js_1 = require("../internal/support/instance-id.js");
|
|
49
|
+
const source_snippet_js_1 = require("../internal/support/source-snippet.js");
|
|
50
|
+
const ci_js_1 = require("../internal/support/ci.js");
|
|
51
|
+
const worker_index_js_1 = require("../internal/support/worker-index.js");
|
|
52
|
+
const cli_filters_js_1 = require("../internal/support/cli-filters.js");
|
|
53
|
+
const global_setup_js_1 = require("./global-setup.js");
|
|
48
54
|
const config_wrapper_js_1 = require("./config-wrapper.js");
|
|
49
|
-
const serializer_js_1 = require("
|
|
50
|
-
const skip_classify_js_1 = require("
|
|
51
|
-
const
|
|
52
|
-
const
|
|
55
|
+
const serializer_js_1 = require("../internal/submit/serializer.js");
|
|
56
|
+
const skip_classify_js_1 = require("../internal/collect/skip-classify.js");
|
|
57
|
+
const error_text_js_1 = require("../internal/collect/error-text.js");
|
|
58
|
+
const run_submitter_js_1 = require("../internal/submit/run-submitter.js");
|
|
59
|
+
const logger_js_1 = require("../internal/support/logger.js");
|
|
53
60
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* stack frames — those live on `error.stack`/`error.location`. The server's
|
|
58
|
-
* locator-healing lookup needs the failing call site to find the pre-captured
|
|
59
|
-
* snapshot for that locator, so when the message has no `at …` frame we append
|
|
60
|
-
* a synthetic one from `error.location`, relativized to the cwd so it matches
|
|
61
|
-
* the format the fixture records at capture time. The frame is appended after
|
|
62
|
-
* the message, where `extractMessageHead` already trims it off before
|
|
63
|
-
* fingerprinting — so failure clustering is unaffected.
|
|
61
|
+
* Relative `file:line:column` location string for a test, normalized to POSIX
|
|
62
|
+
* path separators so Playwright's CLI file filter (and the dashboard's copyable
|
|
63
|
+
* retry command) match on every platform — `path.relative` yields backslashes on Windows.
|
|
64
64
|
*/
|
|
65
|
-
function
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
return null;
|
|
69
|
-
let text = err.message ?? '';
|
|
70
|
-
const loc = err.location;
|
|
71
|
-
if (loc?.file && !/\n\s+at\s/.test(text)) {
|
|
72
|
-
const rel = path.relative(process.cwd(), loc.file).split(path.sep).join('/');
|
|
73
|
-
text += `\n at ${rel}:${loc.line}:${loc.column}`;
|
|
74
|
-
}
|
|
75
|
-
return text;
|
|
65
|
+
function testLocation(test) {
|
|
66
|
+
const relativeFilePath = path.relative(process.cwd(), test.location.file).split(path.sep).join('/');
|
|
67
|
+
return `${relativeFilePath}:${test.location.line}:${test.location.column}`;
|
|
76
68
|
}
|
|
77
69
|
/**
|
|
78
70
|
* Piwi Dashboard Playwright reporter.
|
|
@@ -105,10 +97,10 @@ class PiwiDashboardReporter {
|
|
|
105
97
|
this.streamManager = null;
|
|
106
98
|
/** Track suite-level setup steps (beforeAll/afterAll) not tied to any test */
|
|
107
99
|
this.setupSteps = [];
|
|
108
|
-
this.options = (0,
|
|
100
|
+
this.options = (0, env_js_1.resolveOptions)(rawOptions);
|
|
109
101
|
this.enabled = this.options.enabled !== false && !!this.options.serverUrl;
|
|
110
|
-
this.runLabel = this.options.runLabel || (0,
|
|
111
|
-
this.instanceId = (0,
|
|
102
|
+
this.runLabel = this.options.runLabel || (0, ci_js_1.detectCiRunLabel)();
|
|
103
|
+
this.instanceId = (0, instance_id_js_1.computeInstanceId)(this.options.projectName, this.runLabel);
|
|
112
104
|
const logger = new logger_js_1.Logger(this.options.verbose ?? false);
|
|
113
105
|
this.logger = logger;
|
|
114
106
|
this.httpClient = new http_client_js_1.HttpClient(this.options.serverUrl ?? 'http://localhost:3000', logger);
|
|
@@ -140,7 +132,7 @@ class PiwiDashboardReporter {
|
|
|
140
132
|
const grep = grepRe && grepRe.source !== '.*' ? grepRe.source : undefined;
|
|
141
133
|
const grepInvert = grepInvertRe?.source;
|
|
142
134
|
// File/path filters come from the CLI invocation, not config.grep.
|
|
143
|
-
const fileFilters = (0,
|
|
135
|
+
const fileFilters = (0, cli_filters_js_1.detectCliFileFilters)();
|
|
144
136
|
if (grep || grepInvert || fileFilters.length > 0) {
|
|
145
137
|
this.isFullRun = false;
|
|
146
138
|
this.filterDetails = {
|
|
@@ -166,13 +158,12 @@ class PiwiDashboardReporter {
|
|
|
166
158
|
}
|
|
167
159
|
/** Playwright reporter hook: called when an individual test begins */
|
|
168
160
|
onTestBegin(test, result) {
|
|
169
|
-
const relativeFilePath = path.relative(process.cwd(), test.location.file);
|
|
170
161
|
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
171
162
|
const beginEvent = {
|
|
172
163
|
type: 'begin',
|
|
173
164
|
title: test.title,
|
|
174
|
-
location:
|
|
175
|
-
workerIndex: (0,
|
|
165
|
+
location: testLocation(test),
|
|
166
|
+
workerIndex: (0, worker_index_js_1.workerIndexOf)(result),
|
|
176
167
|
shardIndex: this.shardInfo?.current ?? null,
|
|
177
168
|
browser: this.metadataCollector.getBrowserConfig(test) || undefined,
|
|
178
169
|
suitePath,
|
|
@@ -195,7 +186,7 @@ class PiwiDashboardReporter {
|
|
|
195
186
|
location: step.location ? `${step.location.file}:${step.location.line}:${step.location.column}` : 'unknown',
|
|
196
187
|
stepCategory: cat,
|
|
197
188
|
parentTitle: test?.title || null,
|
|
198
|
-
workerIndex: (0,
|
|
189
|
+
workerIndex: (0, worker_index_js_1.workerIndexOf)(_result),
|
|
199
190
|
startedAt: step.startTime instanceof Date ? step.startTime.getTime() : null,
|
|
200
191
|
};
|
|
201
192
|
this.streamManager?.queueBeginEvent(event);
|
|
@@ -209,7 +200,7 @@ class PiwiDashboardReporter {
|
|
|
209
200
|
return;
|
|
210
201
|
if (cat !== 'hook' && cat !== 'fixture')
|
|
211
202
|
return;
|
|
212
|
-
const workerIndex = (0,
|
|
203
|
+
const workerIndex = (0, worker_index_js_1.workerIndexOf)(_result);
|
|
213
204
|
const startedAt = step.startTime instanceof Date ? step.startTime.getTime() : null;
|
|
214
205
|
const event = {
|
|
215
206
|
type: 'step-end',
|
|
@@ -239,7 +230,6 @@ class PiwiDashboardReporter {
|
|
|
239
230
|
/** Playwright reporter hook: called when an individual test finishes */
|
|
240
231
|
onTestEnd(test, result) {
|
|
241
232
|
this.totalTests++;
|
|
242
|
-
const relativeFilePath = path.relative(process.cwd(), test.location.file);
|
|
243
233
|
this.reportedTestIds.add(test.id);
|
|
244
234
|
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
245
235
|
const annotations = (0, skip_classify_js_1.mergeAnnotations)(test, result);
|
|
@@ -247,12 +237,12 @@ class PiwiDashboardReporter {
|
|
|
247
237
|
const testCase = {
|
|
248
238
|
type: 'complete',
|
|
249
239
|
title: test.title,
|
|
250
|
-
location:
|
|
240
|
+
location: testLocation(test),
|
|
251
241
|
status,
|
|
252
242
|
duration: result.duration,
|
|
253
|
-
error: buildErrorText(result),
|
|
243
|
+
error: (0, error_text_js_1.buildErrorText)(result),
|
|
254
244
|
retries: result.retry,
|
|
255
|
-
workerIndex: (0,
|
|
245
|
+
workerIndex: (0, worker_index_js_1.workerIndexOf)(result),
|
|
256
246
|
shardIndex: this.shardInfo?.current ?? null,
|
|
257
247
|
startedAt: result.startTime ? result.startTime.getTime() : null,
|
|
258
248
|
attachments: result.attachments || [],
|
|
@@ -262,7 +252,8 @@ class PiwiDashboardReporter {
|
|
|
262
252
|
testAnnotations: annotations.length ? annotations : null,
|
|
263
253
|
};
|
|
264
254
|
if (result.status === 'failed' || result.status === 'timedOut') {
|
|
265
|
-
const
|
|
255
|
+
const failingLine = (0, source_snippet_js_1.extractFailingLine)(testCase.error, test.location.file, test.location.line);
|
|
256
|
+
const snippet = (0, source_snippet_js_1.readSourceSnippet)(test.location.file, test.location.line, 30, failingLine);
|
|
266
257
|
if (snippet)
|
|
267
258
|
testCase.testSource = snippet;
|
|
268
259
|
}
|
|
@@ -280,7 +271,7 @@ class PiwiDashboardReporter {
|
|
|
280
271
|
// (captured in the fixture at action call time). No index correlation
|
|
281
272
|
// with pw:api steps — that was unreliable across workers/concurrent calls.
|
|
282
273
|
const locatorAttachment = this.options.captureLocators !== false
|
|
283
|
-
? result.attachments.find((a) => a.name ===
|
|
274
|
+
? result.attachments.find((a) => a.name === attachments_js_1.ATTACHMENT_NAMES.locators)
|
|
284
275
|
: undefined;
|
|
285
276
|
if (locatorAttachment?.body) {
|
|
286
277
|
try {
|
|
@@ -326,12 +317,11 @@ class PiwiDashboardReporter {
|
|
|
326
317
|
for (const test of this.plannedTests) {
|
|
327
318
|
if (this.reportedTestIds.has(test.id))
|
|
328
319
|
continue;
|
|
329
|
-
const relativeFilePath = path.relative(process.cwd(), test.location.file);
|
|
330
320
|
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
331
321
|
const testCase = {
|
|
332
322
|
type: 'complete',
|
|
333
323
|
title: test.title,
|
|
334
|
-
location:
|
|
324
|
+
location: testLocation(test),
|
|
335
325
|
status: 'didnotrun',
|
|
336
326
|
duration: 0,
|
|
337
327
|
error: null,
|
|
@@ -380,4 +370,4 @@ class PiwiDashboardReporter {
|
|
|
380
370
|
}
|
|
381
371
|
exports.PiwiDashboardReporter = PiwiDashboardReporter;
|
|
382
372
|
PiwiDashboardReporter.wrapConfig = config_wrapper_js_1.wrapConfig;
|
|
383
|
-
PiwiDashboardReporter.createGlobalSetup =
|
|
373
|
+
PiwiDashboardReporter.createGlobalSetup = global_setup_js_1.createGlobalSetup;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal collection model — the shapes the reporter accumulates *in process*
|
|
3
|
+
* while a run executes.
|
|
4
|
+
*
|
|
5
|
+
* These are NOT sent to the server verbatim: the wire projection happens in
|
|
6
|
+
* `serializer.ts` (`toWireTestCase` / `serializeRun`) at the JSON boundary. For
|
|
7
|
+
* the external server contract, see `./wire.ts`.
|
|
8
|
+
*/
|
|
9
|
+
import type { BrowserConfig, SuiteConfigEntry, TestAnnotation, TestStepEvent } from './wire.js';
|
|
10
|
+
import type { LocatorSnapshot } from '../internal/capture/locator-healing.js';
|
|
11
|
+
/**
|
|
12
|
+
* A raw Playwright attachment as exposed on `TestResult.attachments`.
|
|
13
|
+
* Carried verbatim on `CollectedTestCase.attachments` so `FileHandler` can
|
|
14
|
+
* resolve trace/attachment paths; never sent to the server.
|
|
15
|
+
*/
|
|
16
|
+
export interface RawAttachment {
|
|
17
|
+
name: string;
|
|
18
|
+
path?: string;
|
|
19
|
+
contentType?: string;
|
|
20
|
+
body?: Buffer;
|
|
21
|
+
originalName?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Performance metrics collected from `result.steps` by `step-analyzer`. */
|
|
24
|
+
export interface CollectedPerformanceMetrics {
|
|
25
|
+
steps: Array<{
|
|
26
|
+
title: string;
|
|
27
|
+
duration: number;
|
|
28
|
+
category: string;
|
|
29
|
+
error?: {
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
failed?: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
totalStepDuration: number;
|
|
35
|
+
slowestStep: {
|
|
36
|
+
title: string;
|
|
37
|
+
duration: number;
|
|
38
|
+
} | null;
|
|
39
|
+
navigationCount: number;
|
|
40
|
+
navigationTotalDuration: number;
|
|
41
|
+
waitTotalDuration: number;
|
|
42
|
+
waitCount: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* What `onTestEnd` accumulates per test case. Mixes three concerns that the
|
|
46
|
+
* reporter must keep together during a run:
|
|
47
|
+
* - **wire fields** (`title`, `status`, `duration`, …) that `toWireTestCase`
|
|
48
|
+
* projects onto `WireTestCase` before sending,
|
|
49
|
+
* - **collection-only state** (`attachments`, `performanceMetrics`,
|
|
50
|
+
* `stepEvents`) consumed by `FileHandler` and the run-level summary,
|
|
51
|
+
* - the `type` discriminant so the same collected object can be queued as a
|
|
52
|
+
* stream event.
|
|
53
|
+
*
|
|
54
|
+
* Upload bookkeeping (`_filesUploaded`) is deliberately NOT on this object —
|
|
55
|
+
* `StreamManager` tracks it in a side `Set` so the data model stays clean.
|
|
56
|
+
*/
|
|
57
|
+
export interface CollectedTestCase {
|
|
58
|
+
/** Stream-event discriminant: `'begin'` or `'complete'`. Omitted for batch-only runs. */
|
|
59
|
+
type?: 'begin' | 'complete';
|
|
60
|
+
title: string;
|
|
61
|
+
location: string;
|
|
62
|
+
status?: string;
|
|
63
|
+
duration?: number;
|
|
64
|
+
error?: string | null;
|
|
65
|
+
retries?: number;
|
|
66
|
+
workerIndex?: number | null;
|
|
67
|
+
shardIndex?: number | null;
|
|
68
|
+
startedAt?: number | null;
|
|
69
|
+
/** Raw Playwright attachments — never sent on the wire. */
|
|
70
|
+
attachments?: RawAttachment[];
|
|
71
|
+
browser?: BrowserConfig | null;
|
|
72
|
+
suitePath?: string[] | null;
|
|
73
|
+
suiteConfig?: SuiteConfigEntry[] | null;
|
|
74
|
+
testAnnotations?: TestAnnotation[] | null;
|
|
75
|
+
/** Source snippet around the failing line (failed/timedOut only). */
|
|
76
|
+
testSource?: string;
|
|
77
|
+
/** Step metrics from `collectStepMetrics`. Consumed by the run summary + `toWireTestCase`. */
|
|
78
|
+
performanceMetrics?: CollectedPerformanceMetrics;
|
|
79
|
+
stepEvents?: TestStepEvent[];
|
|
80
|
+
/** Parsed from `piwi-network` attachments by `FileHandler`. */
|
|
81
|
+
networkRequests?: unknown;
|
|
82
|
+
/** Parsed from `piwi-web-vitals` attachments. */
|
|
83
|
+
webVitals?: unknown;
|
|
84
|
+
/** Parsed from `piwi-console` attachments. */
|
|
85
|
+
consoleLogs?: unknown;
|
|
86
|
+
/** Parsed from `piwi-aria-snapshot` attachment. */
|
|
87
|
+
ariaSnapshot?: string;
|
|
88
|
+
/** Parsed from `piwi-locators` attachment. */
|
|
89
|
+
locatorSnapshots?: LocatorSnapshot[];
|
|
90
|
+
}
|
|
91
|
+
/** Hash + size of a single trace file, used for dedup against the server. */
|
|
92
|
+
export interface TraceHashInfo {
|
|
93
|
+
tracePath: string;
|
|
94
|
+
hash: string;
|
|
95
|
+
size: number;
|
|
96
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Internal collection model — the shapes the reporter accumulates *in process*
|
|
4
|
+
* while a run executes.
|
|
5
|
+
*
|
|
6
|
+
* These are NOT sent to the server verbatim: the wire projection happens in
|
|
7
|
+
* `serializer.ts` (`toWireTestCase` / `serializeRun`) at the JSON boundary. For
|
|
8
|
+
* the external server contract, see `./wire.ts`.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract — the **external** shapes sent to / received from the Piwi
|
|
3
|
+
* Dashboard server.
|
|
4
|
+
*
|
|
5
|
+
* These structurally mirror — but do not import — `application/shared/types.ts`
|
|
6
|
+
* (`TestCasePayload`, `StreamEventPayload`, `TestRunFinishPayload`). Importing
|
|
7
|
+
* that module would leak the monorepo path into the published `.d.ts` files; the
|
|
8
|
+
* constraint forbids the import, not the types. **Any change here is a change to
|
|
9
|
+
* the server contract** — keep both sides structurally compatible.
|
|
10
|
+
*
|
|
11
|
+
* For the in-process collection model (never sent verbatim), see `./collected.ts`.
|
|
12
|
+
*/
|
|
13
|
+
export interface SuiteConfigEntry {
|
|
14
|
+
mode: 'parallel' | 'serial' | 'default';
|
|
15
|
+
annotations: Array<{
|
|
16
|
+
type: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export interface TestAnnotation {
|
|
21
|
+
type: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Filter that narrowed a run to a subset of tests, recorded when `isFullRun`
|
|
26
|
+
* is false. Mirrors `FilterDetails` in `application/shared/types.ts`.
|
|
27
|
+
*/
|
|
28
|
+
export interface FilterDetails {
|
|
29
|
+
/** A non-default `--grep` pattern (Playwright's default `.*` is excluded). */
|
|
30
|
+
grep?: string;
|
|
31
|
+
/** A `--grep-invert` pattern. */
|
|
32
|
+
grepInvert?: string;
|
|
33
|
+
/** Positional file/path filters from the CLI invocation (e.g. ["tests/login.spec.ts"]). */
|
|
34
|
+
files?: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface BrowserConfig {
|
|
37
|
+
projectName?: string;
|
|
38
|
+
browserName?: string | null;
|
|
39
|
+
channel?: string | null;
|
|
40
|
+
viewport?: {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
} | null;
|
|
44
|
+
deviceScaleFactor?: number | null;
|
|
45
|
+
isMobile?: boolean | null;
|
|
46
|
+
hasTouch?: boolean | null;
|
|
47
|
+
locale?: string | null;
|
|
48
|
+
timezoneId?: string | null;
|
|
49
|
+
geolocation?: {
|
|
50
|
+
longitude: number;
|
|
51
|
+
latitude: number;
|
|
52
|
+
accuracy?: number;
|
|
53
|
+
} | null;
|
|
54
|
+
colorScheme?: string | null;
|
|
55
|
+
reducedMotion?: string | null;
|
|
56
|
+
forcedColors?: string | null;
|
|
57
|
+
offline?: boolean | null;
|
|
58
|
+
bypassCSP?: boolean | null;
|
|
59
|
+
javaScriptEnabled?: boolean | null;
|
|
60
|
+
serviceWorkers?: string | null;
|
|
61
|
+
userAgent?: string | null;
|
|
62
|
+
}
|
|
63
|
+
/** A hook/fixture step event with absolute timings (for the workers timeline). */
|
|
64
|
+
export interface TestStepEvent {
|
|
65
|
+
title: string;
|
|
66
|
+
category: 'hook' | 'fixture' | 'test.step' | 'expect' | 'wait';
|
|
67
|
+
startedAt: number;
|
|
68
|
+
duration: number;
|
|
69
|
+
status: string;
|
|
70
|
+
location?: string | null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The per-case wire shape that `toWireTestCase` produces and the server
|
|
74
|
+
* receives. Structurally compatible with `TestCasePayload` and the per-event
|
|
75
|
+
* `StreamEventPayload`.
|
|
76
|
+
*/
|
|
77
|
+
export interface WireTestCase {
|
|
78
|
+
type?: 'begin' | 'complete' | 'step-begin' | 'step-end';
|
|
79
|
+
title: string;
|
|
80
|
+
location: string;
|
|
81
|
+
status?: string;
|
|
82
|
+
duration?: number;
|
|
83
|
+
error?: string | null;
|
|
84
|
+
retries?: number;
|
|
85
|
+
workerIndex?: number | null;
|
|
86
|
+
shardIndex?: number | null;
|
|
87
|
+
startedAt?: number | null;
|
|
88
|
+
steps?: unknown;
|
|
89
|
+
stepEvents?: TestStepEvent[] | null;
|
|
90
|
+
slowestStep?: string | null;
|
|
91
|
+
slowestStepDuration?: number | null;
|
|
92
|
+
wastedTimeMs?: number | null;
|
|
93
|
+
networkRequests?: unknown;
|
|
94
|
+
webVitals?: unknown;
|
|
95
|
+
consoleLogs?: unknown;
|
|
96
|
+
ariaSnapshot?: unknown;
|
|
97
|
+
testSource?: string | null;
|
|
98
|
+
browser?: BrowserConfig | null;
|
|
99
|
+
suitePath?: string[] | null;
|
|
100
|
+
suiteConfig?: SuiteConfigEntry[] | null;
|
|
101
|
+
testAnnotations?: TestAnnotation[] | null;
|
|
102
|
+
/** Step-event discriminant (only for `step-begin`/`step-end` events). */
|
|
103
|
+
stepCategory?: string | null;
|
|
104
|
+
parentTitle?: string | null;
|
|
105
|
+
/** Per-element locator snapshots with ranked alternatives (transient — not stored per-run). */
|
|
106
|
+
locatorSnapshots?: unknown;
|
|
107
|
+
}
|
|
108
|
+
export interface BeginStreamEvent {
|
|
109
|
+
type: 'begin';
|
|
110
|
+
title: string;
|
|
111
|
+
location: string;
|
|
112
|
+
workerIndex: number | null;
|
|
113
|
+
shardIndex: number | null;
|
|
114
|
+
browser?: BrowserConfig | null;
|
|
115
|
+
suitePath?: string[] | null;
|
|
116
|
+
suiteConfig?: SuiteConfigEntry[] | null;
|
|
117
|
+
}
|
|
118
|
+
export interface CompleteStreamEvent {
|
|
119
|
+
type: 'complete';
|
|
120
|
+
title: string;
|
|
121
|
+
location: string;
|
|
122
|
+
status: string;
|
|
123
|
+
duration: number;
|
|
124
|
+
error: string | null;
|
|
125
|
+
retries: number;
|
|
126
|
+
workerIndex: number | null;
|
|
127
|
+
shardIndex: number | null;
|
|
128
|
+
startedAt: number | null;
|
|
129
|
+
browser?: BrowserConfig | null;
|
|
130
|
+
suitePath?: string[] | null;
|
|
131
|
+
suiteConfig?: SuiteConfigEntry[] | null;
|
|
132
|
+
testAnnotations?: TestAnnotation[] | null;
|
|
133
|
+
steps?: unknown;
|
|
134
|
+
stepEvents?: TestStepEvent[] | null;
|
|
135
|
+
slowestStep?: string | null;
|
|
136
|
+
slowestStepDuration?: number | null;
|
|
137
|
+
networkRequests?: unknown;
|
|
138
|
+
webVitals?: unknown;
|
|
139
|
+
consoleLogs?: unknown;
|
|
140
|
+
ariaSnapshot?: unknown;
|
|
141
|
+
testSource?: string | null;
|
|
142
|
+
locatorSnapshots?: unknown;
|
|
143
|
+
}
|
|
144
|
+
export interface StepBeginStreamEvent {
|
|
145
|
+
type: 'step-begin';
|
|
146
|
+
title: string;
|
|
147
|
+
location: string;
|
|
148
|
+
stepCategory: 'hook' | 'fixture';
|
|
149
|
+
parentTitle: string | null;
|
|
150
|
+
workerIndex: number | null;
|
|
151
|
+
startedAt: number | null;
|
|
152
|
+
}
|
|
153
|
+
export interface StepEndStreamEvent {
|
|
154
|
+
type: 'step-end';
|
|
155
|
+
title: string;
|
|
156
|
+
location: string;
|
|
157
|
+
status: string;
|
|
158
|
+
duration: number;
|
|
159
|
+
stepCategory: 'hook' | 'fixture';
|
|
160
|
+
parentTitle: string | null;
|
|
161
|
+
workerIndex: number | null;
|
|
162
|
+
startedAt: number | null;
|
|
163
|
+
}
|
|
164
|
+
/** Discriminated union of events queued to `StreamManager` and persisted by `StreamBuffer`. */
|
|
165
|
+
export type StreamEvent = BeginStreamEvent | CompleteStreamEvent | StepBeginStreamEvent | StepEndStreamEvent;
|
|
166
|
+
export interface SetupStep {
|
|
167
|
+
title: string;
|
|
168
|
+
category: string;
|
|
169
|
+
startedAt: number;
|
|
170
|
+
duration: number;
|
|
171
|
+
status: string;
|
|
172
|
+
location?: string | null;
|
|
173
|
+
workerIndex?: number | null;
|
|
174
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wire contract — the **external** shapes sent to / received from the Piwi
|
|
4
|
+
* Dashboard server.
|
|
5
|
+
*
|
|
6
|
+
* These structurally mirror — but do not import — `application/shared/types.ts`
|
|
7
|
+
* (`TestCasePayload`, `StreamEventPayload`, `TestRunFinishPayload`). Importing
|
|
8
|
+
* that module would leak the monorepo path into the published `.d.ts` files; the
|
|
9
|
+
* constraint forbids the import, not the types. **Any change here is a change to
|
|
10
|
+
* the server contract** — keep both sides structurally compatible.
|
|
11
|
+
*
|
|
12
|
+
* For the in-process collection model (never sent verbatim), see `./collected.ts`.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|