@piwitests/reporter 0.12.0 → 0.13.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/dist/global-setup-module.d.ts +2 -1
- package/dist/global-setup-module.js +432 -3
- package/dist/index.d.ts +204 -8
- package/dist/index.js +4724 -23
- package/dist/internal/capture/attachments.d.ts +8 -3
- package/dist/internal/capture/attachments.js +46 -21
- package/dist/internal/capture/capture-fixtures.d.ts +16 -14
- package/dist/internal/capture/capture-fixtures.js +2211 -971
- package/dist/internal/capture/inspect-on-failure.d.ts +50 -0
- package/dist/internal/capture/inspect-on-failure.js +66 -0
- package/dist/internal/capture/locator-healing.d.ts +33 -190
- package/dist/internal/capture/locator-healing.js +599 -815
- package/dist/internal/capture/pick-on-failure.d.ts +198 -0
- package/dist/internal/capture/pick-on-failure.js +1203 -0
- package/package.json +9 -4
- package/dist/internal/collect/error-text.d.ts +0 -18
- package/dist/internal/collect/error-text.js +0 -79
- package/dist/internal/collect/metadata-collector.d.ts +0 -32
- package/dist/internal/collect/metadata-collector.js +0 -246
- package/dist/internal/collect/skip-classify.d.ts +0 -27
- package/dist/internal/collect/skip-classify.js +0 -40
- package/dist/internal/collect/step-analyzer.d.ts +0 -103
- package/dist/internal/collect/step-analyzer.js +0 -221
- package/dist/internal/config/env.d.ts +0 -46
- package/dist/internal/config/env.js +0 -162
- package/dist/internal/files/compression.d.ts +0 -5
- package/dist/internal/files/compression.js +0 -69
- package/dist/internal/files/file-handler.d.ts +0 -38
- package/dist/internal/files/file-handler.js +0 -207
- package/dist/internal/streaming/crash-recovery.d.ts +0 -23
- package/dist/internal/streaming/crash-recovery.js +0 -106
- package/dist/internal/streaming/stream-buffer.d.ts +0 -17
- package/dist/internal/streaming/stream-buffer.js +0 -102
- package/dist/internal/streaming/stream-manager.d.ts +0 -88
- package/dist/internal/streaming/stream-manager.js +0 -395
- package/dist/internal/submit/run-submitter.d.ts +0 -67
- package/dist/internal/submit/run-submitter.js +0 -190
- package/dist/internal/submit/serializer.d.ts +0 -45
- package/dist/internal/submit/serializer.js +0 -108
- package/dist/internal/submit/uploader.d.ts +0 -89
- package/dist/internal/submit/uploader.js +0 -226
- package/dist/internal/support/ci.d.ts +0 -2
- package/dist/internal/support/ci.js +0 -32
- package/dist/internal/support/cli-filters.d.ts +0 -1
- package/dist/internal/support/cli-filters.js +0 -51
- package/dist/internal/support/errors.d.ts +0 -8
- package/dist/internal/support/errors.js +0 -15
- package/dist/internal/support/instance-id.d.ts +0 -4
- package/dist/internal/support/instance-id.js +0 -48
- package/dist/internal/support/limiter.d.ts +0 -2
- package/dist/internal/support/limiter.js +0 -27
- package/dist/internal/support/logger.d.ts +0 -26
- package/dist/internal/support/logger.js +0 -43
- package/dist/internal/support/reporter-version.d.ts +0 -2
- package/dist/internal/support/reporter-version.js +0 -54
- package/dist/internal/support/setup-file.d.ts +0 -13
- package/dist/internal/support/setup-file.js +0 -61
- package/dist/internal/support/source-snippet.d.ts +0 -12
- package/dist/internal/support/source-snippet.js +0 -97
- package/dist/internal/support/worker-index.d.ts +0 -7
- package/dist/internal/support/worker-index.js +0 -14
- package/dist/internal/transport/http-client.d.ts +0 -52
- package/dist/internal/transport/http-client.js +0 -201
- package/dist/public/config-wrapper.d.ts +0 -21
- package/dist/public/config-wrapper.js +0 -64
- package/dist/public/global-setup.d.ts +0 -13
- package/dist/public/global-setup.js +0 -146
- package/dist/public/options.d.ts +0 -86
- package/dist/public/options.js +0 -2
- package/dist/public/reporter.d.ts +0 -68
- package/dist/public/reporter.js +0 -376
- package/dist/types/collected.d.ts +0 -97
- package/dist/types/collected.js +0 -10
- package/dist/types/wire.d.ts +0 -176
- package/dist/types/wire.js +0 -14
- package/dist/types.d.ts +0 -11
- package/dist/types.js +0 -27
package/dist/public/reporter.js
DELETED
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PiwiDashboardReporter = void 0;
|
|
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 reporter_version_js_1 = require("../internal/support/reporter-version.js");
|
|
50
|
-
const source_snippet_js_1 = require("../internal/support/source-snippet.js");
|
|
51
|
-
const ci_js_1 = require("../internal/support/ci.js");
|
|
52
|
-
const worker_index_js_1 = require("../internal/support/worker-index.js");
|
|
53
|
-
const cli_filters_js_1 = require("../internal/support/cli-filters.js");
|
|
54
|
-
const global_setup_js_1 = require("./global-setup.js");
|
|
55
|
-
const config_wrapper_js_1 = require("./config-wrapper.js");
|
|
56
|
-
const serializer_js_1 = require("../internal/submit/serializer.js");
|
|
57
|
-
const skip_classify_js_1 = require("../internal/collect/skip-classify.js");
|
|
58
|
-
const error_text_js_1 = require("../internal/collect/error-text.js");
|
|
59
|
-
const run_submitter_js_1 = require("../internal/submit/run-submitter.js");
|
|
60
|
-
const logger_js_1 = require("../internal/support/logger.js");
|
|
61
|
-
/**
|
|
62
|
-
* Relative `file:line:column` location string for a test, normalized to POSIX
|
|
63
|
-
* path separators so Playwright's CLI file filter (and the dashboard's copyable
|
|
64
|
-
* retry command) match on every platform — `path.relative` yields backslashes on Windows.
|
|
65
|
-
*/
|
|
66
|
-
function testLocation(test) {
|
|
67
|
-
const relativeFilePath = path.relative(process.cwd(), test.location.file).split(path.sep).join('/');
|
|
68
|
-
return `${relativeFilePath}:${test.location.line}:${test.location.column}`;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Piwi Dashboard Playwright reporter.
|
|
72
|
-
*
|
|
73
|
-
* Collects test results, metadata, performance metrics and trace files, then
|
|
74
|
-
* hands the collected run to a `RunSubmitter` which drives the JSON / multipart
|
|
75
|
-
* / streaming submit ladder. The reporter itself only owns the Playwright hooks
|
|
76
|
-
* and the running counters.
|
|
77
|
-
*/
|
|
78
|
-
class PiwiDashboardReporter {
|
|
79
|
-
constructor(rawOptions = {}) {
|
|
80
|
-
this.testCases = [];
|
|
81
|
-
this.startTime = null;
|
|
82
|
-
this.playwrightVersion = null;
|
|
83
|
-
this.reporterVersion = (0, reporter_version_js_1.getReporterVersion)();
|
|
84
|
-
this.totalTests = 0;
|
|
85
|
-
this.passedTests = 0;
|
|
86
|
-
this.failedTests = 0;
|
|
87
|
-
this.skippedTests = 0;
|
|
88
|
-
this.timedOutTests = 0;
|
|
89
|
-
this.didNotRunTests = 0;
|
|
90
|
-
/** Full set of tests Playwright planned to run this shard (captured in `onBegin`). */
|
|
91
|
-
this.plannedTests = [];
|
|
92
|
-
/** Ids of tests that actually reported via `onTestEnd`, to find the ones that never ran. */
|
|
93
|
-
this.reportedTestIds = new Set();
|
|
94
|
-
this.runLabel = null;
|
|
95
|
-
this.shardInfo = null;
|
|
96
|
-
this.metadata = {};
|
|
97
|
-
this.isFullRun = true;
|
|
98
|
-
this.filterDetails = null;
|
|
99
|
-
this.streamManager = null;
|
|
100
|
-
/** Track suite-level setup steps (beforeAll/afterAll) not tied to any test */
|
|
101
|
-
this.setupSteps = [];
|
|
102
|
-
this.options = (0, env_js_1.resolveOptions)(rawOptions);
|
|
103
|
-
this.enabled = this.options.enabled !== false && !!this.options.serverUrl;
|
|
104
|
-
this.runLabel = this.options.runLabel || (0, ci_js_1.detectCiRunLabel)();
|
|
105
|
-
this.instanceId = (0, instance_id_js_1.computeInstanceId)(this.options.projectName, this.runLabel);
|
|
106
|
-
const logger = new logger_js_1.Logger(this.options.verbose ?? false);
|
|
107
|
-
this.logger = logger;
|
|
108
|
-
this.httpClient = new http_client_js_1.HttpClient(this.options.serverUrl ?? 'http://localhost:3000', logger);
|
|
109
|
-
this.fileHandler = new file_handler_js_1.FileHandler(logger);
|
|
110
|
-
this.uploader = new uploader_js_1.Uploader(this.httpClient, this.fileHandler, logger);
|
|
111
|
-
this.recovery = new crash_recovery_js_1.CrashRecovery(this.options.projectName, logger);
|
|
112
|
-
this.metadataCollector = new metadata_collector_js_1.MetadataCollector(logger);
|
|
113
|
-
const streamBuffer = new stream_buffer_js_1.StreamBuffer(this.options.projectName);
|
|
114
|
-
streamBuffer.clearStale();
|
|
115
|
-
if (this.options.streaming) {
|
|
116
|
-
this.streamManager = new stream_manager_js_1.StreamManager(this.httpClient, streamBuffer, this.recovery, this.uploader, this.fileHandler, this.options, logger);
|
|
117
|
-
}
|
|
118
|
-
this.submitter = new run_submitter_js_1.RunSubmitter(this.httpClient, this.uploader, this.recovery, this.streamManager, logger);
|
|
119
|
-
}
|
|
120
|
-
/** Playwright reporter hook: called once at the start of the test run */
|
|
121
|
-
onBegin(config, suite) {
|
|
122
|
-
if (!this.enabled) {
|
|
123
|
-
this.logger.info('Not enabled — set PIWI_DASHBOARD_URL or serverUrl to enable.');
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
this.startTime = new Date().toISOString();
|
|
127
|
-
this.playwrightVersion = config.version;
|
|
128
|
-
this.logger.info(`Starting test run for project: ${this.options.projectName} (Playwright v${this.playwrightVersion})`);
|
|
129
|
-
// Detect partial-run filters so the dashboard can distinguish full-suite runs from ad-hoc focused runs.
|
|
130
|
-
const rawConfig = config;
|
|
131
|
-
const grepRe = rawConfig.grep instanceof RegExp ? rawConfig.grep : undefined;
|
|
132
|
-
const grepInvertRe = rawConfig.grepInvert instanceof RegExp ? rawConfig.grepInvert : undefined;
|
|
133
|
-
// Playwright's default grep is /.*/ (matches everything) — only a non-default pattern is a real filter.
|
|
134
|
-
const grep = grepRe && grepRe.source !== '.*' ? grepRe.source : undefined;
|
|
135
|
-
const grepInvert = grepInvertRe?.source;
|
|
136
|
-
// File/path filters come from the CLI invocation, not config.grep.
|
|
137
|
-
const fileFilters = (0, cli_filters_js_1.detectCliFileFilters)();
|
|
138
|
-
if (grep || grepInvert || fileFilters.length > 0) {
|
|
139
|
-
this.isFullRun = false;
|
|
140
|
-
this.filterDetails = {
|
|
141
|
-
...(grep ? { grep } : {}),
|
|
142
|
-
...(grepInvert ? { grepInvert } : {}),
|
|
143
|
-
...(fileFilters.length > 0 ? { files: fileFilters } : {}),
|
|
144
|
-
};
|
|
145
|
-
this.logger.info('Partial run detected (filter active)');
|
|
146
|
-
}
|
|
147
|
-
this.metadata = this.metadataCollector.collect(config, suite, this.options);
|
|
148
|
-
// Snapshot the planned test list so `onEnd` can materialize tests that
|
|
149
|
-
// never ran (e.g. cut short by `maxFailures`) as `didnotrun` cases. The
|
|
150
|
-
// suite is already filtered/sharded, so this matches what this shard
|
|
151
|
-
// attempts.
|
|
152
|
-
this.plannedTests = suite.allTests();
|
|
153
|
-
// Detect Playwright shard config (--shard=1/3)
|
|
154
|
-
const pwShard = config.shard;
|
|
155
|
-
if (pwShard?.total && pwShard.total > 1) {
|
|
156
|
-
this.shardInfo = { current: pwShard.current, total: pwShard.total };
|
|
157
|
-
this.logger.info(`Shard ${this.shardInfo.current}/${this.shardInfo.total} detected`);
|
|
158
|
-
}
|
|
159
|
-
this.streamManager?.start(this.startTime, this.metadata, this.instanceId, this.playwrightVersion, this.reporterVersion, this.shardInfo, this.isFullRun, this.filterDetails);
|
|
160
|
-
}
|
|
161
|
-
/** Playwright reporter hook: called when an individual test begins */
|
|
162
|
-
onTestBegin(test, result) {
|
|
163
|
-
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
164
|
-
const beginEvent = {
|
|
165
|
-
type: 'begin',
|
|
166
|
-
title: test.title,
|
|
167
|
-
location: testLocation(test),
|
|
168
|
-
workerIndex: (0, worker_index_js_1.workerIndexOf)(result),
|
|
169
|
-
shardIndex: this.shardInfo?.current ?? null,
|
|
170
|
-
browser: this.metadataCollector.getBrowserConfig(test) || undefined,
|
|
171
|
-
suitePath,
|
|
172
|
-
suiteConfig,
|
|
173
|
-
};
|
|
174
|
-
if (this.streamManager) {
|
|
175
|
-
this.streamManager.queueBeginEvent((0, serializer_js_1.toWireTestCase)(beginEvent));
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/** Playwright reporter hook: called when a step (including hook/fixture) begins */
|
|
179
|
-
onStepBegin(test, _result, step) {
|
|
180
|
-
if (!this.enabled || !this.streamManager?.enabled)
|
|
181
|
-
return;
|
|
182
|
-
const cat = step.category;
|
|
183
|
-
if (cat !== 'hook' && cat !== 'fixture')
|
|
184
|
-
return;
|
|
185
|
-
const event = {
|
|
186
|
-
type: 'step-begin',
|
|
187
|
-
title: step.title,
|
|
188
|
-
location: step.location ? `${step.location.file}:${step.location.line}:${step.location.column}` : 'unknown',
|
|
189
|
-
stepCategory: cat,
|
|
190
|
-
parentTitle: test?.title || null,
|
|
191
|
-
workerIndex: (0, worker_index_js_1.workerIndexOf)(_result),
|
|
192
|
-
startedAt: step.startTime instanceof Date ? step.startTime.getTime() : null,
|
|
193
|
-
};
|
|
194
|
-
this.streamManager?.queueBeginEvent(event);
|
|
195
|
-
}
|
|
196
|
-
/** Playwright reporter hook: called when a step (including hook/fixture) ends */
|
|
197
|
-
onStepEnd(test, _result, step) {
|
|
198
|
-
const cat = step.category;
|
|
199
|
-
if (cat === 'pw:api')
|
|
200
|
-
return; // not surfaced as stream events; locator locations are captured in the fixture
|
|
201
|
-
if (!this.enabled || !this.streamManager?.enabled)
|
|
202
|
-
return;
|
|
203
|
-
if (cat !== 'hook' && cat !== 'fixture')
|
|
204
|
-
return;
|
|
205
|
-
const workerIndex = (0, worker_index_js_1.workerIndexOf)(_result);
|
|
206
|
-
const startedAt = step.startTime instanceof Date ? step.startTime.getTime() : null;
|
|
207
|
-
const event = {
|
|
208
|
-
type: 'step-end',
|
|
209
|
-
title: step.title,
|
|
210
|
-
location: step.location ? `${step.location.file}:${step.location.line}:${step.location.column}` : 'unknown',
|
|
211
|
-
status: step.error ? 'failed' : 'passed',
|
|
212
|
-
duration: step.duration || 0,
|
|
213
|
-
stepCategory: cat,
|
|
214
|
-
parentTitle: test?.title || null,
|
|
215
|
-
workerIndex,
|
|
216
|
-
startedAt,
|
|
217
|
-
};
|
|
218
|
-
this.streamManager?.queueEvent(event);
|
|
219
|
-
// Track suite-level hooks (beforeAll/afterAll) for the timeline
|
|
220
|
-
if (!test && startedAt) {
|
|
221
|
-
this.setupSteps.push({
|
|
222
|
-
title: step.title,
|
|
223
|
-
category: cat,
|
|
224
|
-
startedAt,
|
|
225
|
-
duration: step.duration || 0,
|
|
226
|
-
status: step.error ? 'failed' : 'passed',
|
|
227
|
-
location: step.location ? `${step.location.file}:${step.location.line}:${step.location.column}` : null,
|
|
228
|
-
workerIndex,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
/** Playwright reporter hook: called when an individual test finishes */
|
|
233
|
-
onTestEnd(test, result) {
|
|
234
|
-
this.totalTests++;
|
|
235
|
-
this.reportedTestIds.add(test.id);
|
|
236
|
-
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
237
|
-
const annotations = (0, skip_classify_js_1.mergeAnnotations)(test, result);
|
|
238
|
-
const status = (0, skip_classify_js_1.classifyStatus)(result.status, annotations);
|
|
239
|
-
const testCase = {
|
|
240
|
-
type: 'complete',
|
|
241
|
-
title: test.title,
|
|
242
|
-
location: testLocation(test),
|
|
243
|
-
status,
|
|
244
|
-
duration: result.duration,
|
|
245
|
-
error: (0, error_text_js_1.buildErrorText)(result),
|
|
246
|
-
retries: result.retry,
|
|
247
|
-
workerIndex: (0, worker_index_js_1.workerIndexOf)(result),
|
|
248
|
-
shardIndex: this.shardInfo?.current ?? null,
|
|
249
|
-
startedAt: result.startTime ? result.startTime.getTime() : null,
|
|
250
|
-
attachments: result.attachments || [],
|
|
251
|
-
browser: this.metadataCollector.getBrowserConfig(test) || undefined,
|
|
252
|
-
suitePath,
|
|
253
|
-
suiteConfig,
|
|
254
|
-
testAnnotations: annotations.length ? annotations : null,
|
|
255
|
-
};
|
|
256
|
-
if (result.status === 'failed' || result.status === 'timedOut') {
|
|
257
|
-
const failingLine = (0, source_snippet_js_1.extractFailingLine)(testCase.error, test.location.file, test.location.line);
|
|
258
|
-
const snippet = (0, source_snippet_js_1.readSourceSnippet)(test.location.file, test.location.line, 30, failingLine);
|
|
259
|
-
if (snippet)
|
|
260
|
-
testCase.testSource = snippet;
|
|
261
|
-
}
|
|
262
|
-
if (this.options.collectPerformanceMetrics && result.steps?.length > 0) {
|
|
263
|
-
testCase.performanceMetrics = (0, step_analyzer_js_1.collectStepMetrics)(result.steps);
|
|
264
|
-
const stepEvents = (0, step_analyzer_js_1.extractTestStepEvents)(result.steps, result.startTime);
|
|
265
|
-
const waitEvents = (0, step_analyzer_js_1.extractWaitEvents)(result.steps);
|
|
266
|
-
const allEvents = [...stepEvents, ...waitEvents];
|
|
267
|
-
if (allEvents.length > 0)
|
|
268
|
-
testCase.stepEvents = allEvents;
|
|
269
|
-
}
|
|
270
|
-
if (this.options.collectPerformanceMetrics && result.attachments) {
|
|
271
|
-
this.fileHandler.parsePerformanceAttachments(testCase, result.attachments);
|
|
272
|
-
// Locator snapshots arrive pre-stamped with their call-site `location`
|
|
273
|
-
// (captured in the fixture at action call time). No index correlation
|
|
274
|
-
// with pw:api steps — that was unreliable across workers/concurrent calls.
|
|
275
|
-
const locatorAttachment = this.options.captureLocators !== false
|
|
276
|
-
? result.attachments.find((a) => a.name === attachments_js_1.ATTACHMENT_NAMES.locators)
|
|
277
|
-
: undefined;
|
|
278
|
-
if (locatorAttachment?.body) {
|
|
279
|
-
try {
|
|
280
|
-
testCase.locatorSnapshots = JSON.parse(locatorAttachment.body.toString());
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
/* ignore parse errors */
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
switch (status) {
|
|
288
|
-
case 'passed':
|
|
289
|
-
this.passedTests++;
|
|
290
|
-
break;
|
|
291
|
-
case 'failed':
|
|
292
|
-
this.failedTests++;
|
|
293
|
-
break;
|
|
294
|
-
case 'skipped':
|
|
295
|
-
this.skippedTests++;
|
|
296
|
-
break;
|
|
297
|
-
case 'didnotrun':
|
|
298
|
-
this.didNotRunTests++;
|
|
299
|
-
break;
|
|
300
|
-
case 'timedOut':
|
|
301
|
-
this.timedOutTests++;
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
this.testCases.push(testCase);
|
|
305
|
-
if (this.streamManager) {
|
|
306
|
-
this.streamManager.queueEvent((0, serializer_js_1.toWireTestCase)(testCase));
|
|
307
|
-
if (this.options.liveFileUploads)
|
|
308
|
-
this.streamManager.scheduleLiveUpload(testCase);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Synthesize `didnotrun` cases for tests Playwright planned but never reported
|
|
313
|
-
* (no `onTestEnd`) — typically because `maxFailures` cut the run short. These
|
|
314
|
-
* carry no result, so they're emitted with zero duration and no error. In
|
|
315
|
-
* streaming mode they're queued as complete events so the pre-finish drain
|
|
316
|
-
* sends them alongside the rest.
|
|
317
|
-
*/
|
|
318
|
-
materializeUnrunTests() {
|
|
319
|
-
for (const test of this.plannedTests) {
|
|
320
|
-
if (this.reportedTestIds.has(test.id))
|
|
321
|
-
continue;
|
|
322
|
-
const { suitePath, suiteConfig } = this.metadataCollector.getSuiteInfo(test);
|
|
323
|
-
const testCase = {
|
|
324
|
-
type: 'complete',
|
|
325
|
-
title: test.title,
|
|
326
|
-
location: testLocation(test),
|
|
327
|
-
status: 'didnotrun',
|
|
328
|
-
duration: 0,
|
|
329
|
-
error: null,
|
|
330
|
-
retries: 0,
|
|
331
|
-
workerIndex: null,
|
|
332
|
-
shardIndex: this.shardInfo?.current ?? null,
|
|
333
|
-
startedAt: null,
|
|
334
|
-
attachments: [],
|
|
335
|
-
browser: this.metadataCollector.getBrowserConfig(test) || undefined,
|
|
336
|
-
suitePath,
|
|
337
|
-
suiteConfig,
|
|
338
|
-
testAnnotations: test.annotations?.length ? test.annotations : null,
|
|
339
|
-
};
|
|
340
|
-
this.testCases.push(testCase);
|
|
341
|
-
this.totalTests++;
|
|
342
|
-
this.didNotRunTests++;
|
|
343
|
-
if (this.streamManager) {
|
|
344
|
-
this.streamManager.queueEvent((0, serializer_js_1.toWireTestCase)(testCase));
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
/** Playwright reporter hook: called when the full test run finishes */
|
|
349
|
-
async onEnd(result) {
|
|
350
|
-
if (!this.enabled)
|
|
351
|
-
return;
|
|
352
|
-
this.materializeUnrunTests();
|
|
353
|
-
await this.submitter.submit({
|
|
354
|
-
options: this.options,
|
|
355
|
-
testCases: this.testCases,
|
|
356
|
-
startTime: this.startTime,
|
|
357
|
-
playwrightVersion: this.playwrightVersion,
|
|
358
|
-
reporterVersion: this.reporterVersion,
|
|
359
|
-
totalTests: this.totalTests,
|
|
360
|
-
passedTests: this.passedTests,
|
|
361
|
-
failedTests: this.failedTests,
|
|
362
|
-
skippedTests: this.skippedTests,
|
|
363
|
-
timedOutTests: this.timedOutTests,
|
|
364
|
-
didNotRunTests: this.didNotRunTests,
|
|
365
|
-
metadata: this.metadata,
|
|
366
|
-
instanceId: this.instanceId,
|
|
367
|
-
shardInfo: this.shardInfo,
|
|
368
|
-
setupSteps: this.setupSteps,
|
|
369
|
-
isFullRun: this.isFullRun,
|
|
370
|
-
filterDetails: this.filterDetails,
|
|
371
|
-
}, result);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
exports.PiwiDashboardReporter = PiwiDashboardReporter;
|
|
375
|
-
PiwiDashboardReporter.wrapConfig = config_wrapper_js_1.wrapConfig;
|
|
376
|
-
PiwiDashboardReporter.createGlobalSetup = global_setup_js_1.createGlobalSetup;
|
|
@@ -1,97 +0,0 @@
|
|
|
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
|
-
pageState?: unknown;
|
|
85
|
-
/** Parsed from `piwi-console` attachments. */
|
|
86
|
-
consoleLogs?: unknown;
|
|
87
|
-
/** Parsed from `piwi-aria-snapshot` attachment. */
|
|
88
|
-
ariaSnapshot?: string;
|
|
89
|
-
/** Parsed from `piwi-locators` attachment. */
|
|
90
|
-
locatorSnapshots?: LocatorSnapshot[];
|
|
91
|
-
}
|
|
92
|
-
/** Hash + size of a single trace file, used for dedup against the server. */
|
|
93
|
-
export interface TraceHashInfo {
|
|
94
|
-
tracePath: string;
|
|
95
|
-
hash: string;
|
|
96
|
-
size: number;
|
|
97
|
-
}
|
package/dist/types/collected.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
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 });
|
package/dist/types/wire.d.ts
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
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
|
-
pageState?: unknown;
|
|
96
|
-
consoleLogs?: unknown;
|
|
97
|
-
ariaSnapshot?: unknown;
|
|
98
|
-
testSource?: string | null;
|
|
99
|
-
browser?: BrowserConfig | null;
|
|
100
|
-
suitePath?: string[] | null;
|
|
101
|
-
suiteConfig?: SuiteConfigEntry[] | null;
|
|
102
|
-
testAnnotations?: TestAnnotation[] | null;
|
|
103
|
-
/** Step-event discriminant (only for `step-begin`/`step-end` events). */
|
|
104
|
-
stepCategory?: string | null;
|
|
105
|
-
parentTitle?: string | null;
|
|
106
|
-
/** Per-element locator snapshots with ranked alternatives (transient — not stored per-run). */
|
|
107
|
-
locatorSnapshots?: unknown;
|
|
108
|
-
}
|
|
109
|
-
export interface BeginStreamEvent {
|
|
110
|
-
type: 'begin';
|
|
111
|
-
title: string;
|
|
112
|
-
location: string;
|
|
113
|
-
workerIndex: number | null;
|
|
114
|
-
shardIndex: number | null;
|
|
115
|
-
browser?: BrowserConfig | null;
|
|
116
|
-
suitePath?: string[] | null;
|
|
117
|
-
suiteConfig?: SuiteConfigEntry[] | null;
|
|
118
|
-
}
|
|
119
|
-
export interface CompleteStreamEvent {
|
|
120
|
-
type: 'complete';
|
|
121
|
-
title: string;
|
|
122
|
-
location: string;
|
|
123
|
-
status: string;
|
|
124
|
-
duration: number;
|
|
125
|
-
error: string | null;
|
|
126
|
-
retries: number;
|
|
127
|
-
workerIndex: number | null;
|
|
128
|
-
shardIndex: number | null;
|
|
129
|
-
startedAt: number | null;
|
|
130
|
-
browser?: BrowserConfig | null;
|
|
131
|
-
suitePath?: string[] | null;
|
|
132
|
-
suiteConfig?: SuiteConfigEntry[] | null;
|
|
133
|
-
testAnnotations?: TestAnnotation[] | null;
|
|
134
|
-
steps?: unknown;
|
|
135
|
-
stepEvents?: TestStepEvent[] | null;
|
|
136
|
-
slowestStep?: string | null;
|
|
137
|
-
slowestStepDuration?: number | null;
|
|
138
|
-
networkRequests?: unknown;
|
|
139
|
-
webVitals?: unknown;
|
|
140
|
-
pageState?: unknown;
|
|
141
|
-
consoleLogs?: unknown;
|
|
142
|
-
ariaSnapshot?: unknown;
|
|
143
|
-
testSource?: string | null;
|
|
144
|
-
locatorSnapshots?: unknown;
|
|
145
|
-
}
|
|
146
|
-
export interface StepBeginStreamEvent {
|
|
147
|
-
type: 'step-begin';
|
|
148
|
-
title: string;
|
|
149
|
-
location: string;
|
|
150
|
-
stepCategory: 'hook' | 'fixture';
|
|
151
|
-
parentTitle: string | null;
|
|
152
|
-
workerIndex: number | null;
|
|
153
|
-
startedAt: number | null;
|
|
154
|
-
}
|
|
155
|
-
export interface StepEndStreamEvent {
|
|
156
|
-
type: 'step-end';
|
|
157
|
-
title: string;
|
|
158
|
-
location: string;
|
|
159
|
-
status: string;
|
|
160
|
-
duration: number;
|
|
161
|
-
stepCategory: 'hook' | 'fixture';
|
|
162
|
-
parentTitle: string | null;
|
|
163
|
-
workerIndex: number | null;
|
|
164
|
-
startedAt: number | null;
|
|
165
|
-
}
|
|
166
|
-
/** Discriminated union of events queued to `StreamManager` and persisted by `StreamBuffer`. */
|
|
167
|
-
export type StreamEvent = BeginStreamEvent | CompleteStreamEvent | StepBeginStreamEvent | StepEndStreamEvent;
|
|
168
|
-
export interface SetupStep {
|
|
169
|
-
title: string;
|
|
170
|
-
category: string;
|
|
171
|
-
startedAt: number;
|
|
172
|
-
duration: number;
|
|
173
|
-
status: string;
|
|
174
|
-
location?: string | null;
|
|
175
|
-
workerIndex?: number | null;
|
|
176
|
-
}
|
package/dist/types/wire.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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 });
|
package/dist/types.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reporter-local domain model, split by audience:
|
|
3
|
-
* - `types/wire.ts` — the **external** contract sent to / received from the server.
|
|
4
|
-
* - `types/collected.ts` — the **internal** model the reporter accumulates in process.
|
|
5
|
-
*
|
|
6
|
-
* This barrel re-exports both so `./types.js` imports keep resolving. Prefer
|
|
7
|
-
* importing from the specific module (`./types/wire.js` / `./types/collected.js`)
|
|
8
|
-
* so each import site shows whether it touches the wire contract or the internal model.
|
|
9
|
-
*/
|
|
10
|
-
export * from './types/wire.js';
|
|
11
|
-
export * from './types/collected.js';
|