@arghajit/playwright-pulse-report 0.2.1 → 0.2.3
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 +91 -77
- package/dist/reporter/attachment-utils.js +41 -33
- package/dist/reporter/playwright-pulse-reporter.d.ts +2 -0
- package/dist/reporter/playwright-pulse-reporter.js +146 -103
- package/dist/types/index.d.ts +23 -1
- package/package.json +17 -52
- package/scripts/generate-email-report.mjs +714 -0
- package/scripts/generate-report.mjs +2341 -0
- package/scripts/generate-static-report.mjs +1188 -1046
- package/scripts/generate-trend.mjs +1 -1
- package/scripts/merge-pulse-report.js +1 -0
- package/scripts/{sendReport.js → sendReport.mjs} +143 -76
- package/screenshots/127-0-0-1-5500-pulse-report-output-playwright-pulse-static-report-html-i-Phone-14-Pro-Max-1.png +0 -0
- package/screenshots/127-0-0-1-5500-pulse-report-output-playwright-pulse-static-report-html-i-Phone-14-Pro-Max.png +0 -0
- package/screenshots/Email-report.jpg +0 -0
- package/screenshots/Users-arghajitsingha-Downloads-pulse-report-1-playwright-pulse-static-report-html-1.png +0 -0
- package/screenshots/Users-arghajitsingha-Downloads-pulse-report-1-playwright-pulse-static-report-html-2.png +0 -0
- package/screenshots/Users-arghajitsingha-Downloads-pulse-report-1-playwright-pulse-static-report-html.png +0 -0
- package/screenshots/image.png +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// input_file_0.ts
|
|
3
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
3
|
if (k2 === undefined) k2 = k;
|
|
5
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -38,7 +37,8 @@ exports.PlaywrightPulseReporter = void 0;
|
|
|
38
37
|
const fs = __importStar(require("fs/promises"));
|
|
39
38
|
const path = __importStar(require("path"));
|
|
40
39
|
const crypto_1 = require("crypto");
|
|
41
|
-
const
|
|
40
|
+
const ua_parser_js_1 = require("ua-parser-js");
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
42
|
const convertStatus = (status, testCase) => {
|
|
43
43
|
if ((testCase === null || testCase === void 0 ? void 0 : testCase.expectedStatus) === "failed") {
|
|
44
44
|
return "failed";
|
|
@@ -105,9 +105,59 @@ class PlaywrightPulseReporter {
|
|
|
105
105
|
.catch((err) => console.error("Pulse Reporter: Error during initialization:", err));
|
|
106
106
|
}
|
|
107
107
|
onTestBegin(test) {
|
|
108
|
-
|
|
108
|
+
console.log(`Starting test: ${test.title}`);
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
getBrowserDetails(test) {
|
|
111
|
+
var _a, _b, _c, _d;
|
|
112
|
+
const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
|
|
113
|
+
const projectConfig = project === null || project === void 0 ? void 0 : project.use;
|
|
114
|
+
const userAgent = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.userAgent;
|
|
115
|
+
const configuredBrowserType = (_b = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.browserName) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
116
|
+
const parser = new ua_parser_js_1.UAParser(userAgent);
|
|
117
|
+
const result = parser.getResult();
|
|
118
|
+
let browserName = result.browser.name;
|
|
119
|
+
const browserVersion = result.browser.version
|
|
120
|
+
? ` v${result.browser.version.split(".")[0]}`
|
|
121
|
+
: "";
|
|
122
|
+
const osName = result.os.name ? ` on ${result.os.name}` : "";
|
|
123
|
+
const osVersion = result.os.version
|
|
124
|
+
? ` ${result.os.version.split(".")[0]}`
|
|
125
|
+
: "";
|
|
126
|
+
const deviceType = result.device.type;
|
|
127
|
+
let finalString;
|
|
128
|
+
if (browserName === undefined) {
|
|
129
|
+
browserName = configuredBrowserType;
|
|
130
|
+
finalString = `${browserName}`;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
if (deviceType === "mobile" || deviceType === "tablet") {
|
|
134
|
+
if ((_c = result.os.name) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes("android")) {
|
|
135
|
+
if (browserName.toLowerCase().includes("chrome"))
|
|
136
|
+
browserName = "Chrome Mobile";
|
|
137
|
+
else if (browserName.toLowerCase().includes("firefox"))
|
|
138
|
+
browserName = "Firefox Mobile";
|
|
139
|
+
else if (result.engine.name === "Blink" && !result.browser.name)
|
|
140
|
+
browserName = "Android WebView";
|
|
141
|
+
else if (browserName &&
|
|
142
|
+
!browserName.toLowerCase().includes("mobile")) {
|
|
143
|
+
// Keep it as is
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
browserName = "Android Browser";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else if ((_d = result.os.name) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes("ios")) {
|
|
150
|
+
browserName = "Mobile Safari";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (browserName === "Electron") {
|
|
154
|
+
browserName = "Electron App";
|
|
155
|
+
}
|
|
156
|
+
finalString = `${browserName}${browserVersion}${osName}${osVersion}`;
|
|
157
|
+
}
|
|
158
|
+
return finalString.trim();
|
|
159
|
+
}
|
|
160
|
+
async processStep(step, testId, browserDetails, testCase) {
|
|
111
161
|
var _a, _b, _c, _d;
|
|
112
162
|
let stepStatus = "passed";
|
|
113
163
|
let errorMessage = ((_a = step.error) === null || _a === void 0 ? void 0 : _a.message) || undefined;
|
|
@@ -124,15 +174,14 @@ class PlaywrightPulseReporter {
|
|
|
124
174
|
if (step.location) {
|
|
125
175
|
codeLocation = `${path.relative(this.config.rootDir, step.location.file)}:${step.location.line}:${step.location.column}`;
|
|
126
176
|
}
|
|
127
|
-
let stepTitle = step.title;
|
|
128
177
|
return {
|
|
129
178
|
id: `${testId}_step_${startTime.toISOString()}-${duration}-${(0, crypto_1.randomUUID)()}`,
|
|
130
|
-
title:
|
|
179
|
+
title: step.title,
|
|
131
180
|
status: stepStatus,
|
|
132
181
|
duration: duration,
|
|
133
182
|
startTime: startTime,
|
|
134
183
|
endTime: endTime,
|
|
135
|
-
browser:
|
|
184
|
+
browser: browserDetails,
|
|
136
185
|
errorMessage: errorMessage,
|
|
137
186
|
stackTrace: ((_d = step.error) === null || _d === void 0 ? void 0 : _d.stack) || undefined,
|
|
138
187
|
codeLocation: codeLocation || undefined,
|
|
@@ -146,21 +195,16 @@ class PlaywrightPulseReporter {
|
|
|
146
195
|
};
|
|
147
196
|
}
|
|
148
197
|
async onTestEnd(test, result) {
|
|
149
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
198
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
150
199
|
const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
|
|
151
|
-
const
|
|
200
|
+
const browserDetails = this.getBrowserDetails(test);
|
|
152
201
|
const testStatus = convertStatus(result.status, test);
|
|
153
202
|
const startTime = new Date(result.startTime);
|
|
154
203
|
const endTime = new Date(startTime.getTime() + result.duration);
|
|
155
|
-
const testIdForFiles = test.id ||
|
|
156
|
-
`${test
|
|
157
|
-
.titlePath()
|
|
158
|
-
.join("_")
|
|
159
|
-
.replace(/[^a-zA-Z0-9]/g, "_")}_${startTime.getTime()}`;
|
|
160
204
|
const processAllSteps = async (steps) => {
|
|
161
205
|
let processed = [];
|
|
162
206
|
for (const step of steps) {
|
|
163
|
-
const processedStep = await this.processStep(step,
|
|
207
|
+
const processedStep = await this.processStep(step, test.id, browserDetails, test);
|
|
164
208
|
processed.push(processedStep);
|
|
165
209
|
if (step.steps && step.steps.length > 0) {
|
|
166
210
|
processedStep.steps = await processAllSteps(step.steps);
|
|
@@ -170,7 +214,7 @@ class PlaywrightPulseReporter {
|
|
|
170
214
|
};
|
|
171
215
|
let codeSnippet = undefined;
|
|
172
216
|
try {
|
|
173
|
-
if (((
|
|
217
|
+
if (((_b = test.location) === null || _b === void 0 ? void 0 : _b.file) && ((_c = test.location) === null || _c === void 0 ? void 0 : _c.line) && ((_d = test.location) === null || _d === void 0 ? void 0 : _d.column)) {
|
|
174
218
|
const relativePath = path.relative(this.config.rootDir, test.location.file);
|
|
175
219
|
codeSnippet = `Test defined at: ${relativePath}:${test.location.line}:${test.location.column}`;
|
|
176
220
|
}
|
|
@@ -178,48 +222,87 @@ class PlaywrightPulseReporter {
|
|
|
178
222
|
catch (e) {
|
|
179
223
|
console.warn(`Pulse Reporter: Could not extract code snippet for ${test.title}`, e);
|
|
180
224
|
}
|
|
181
|
-
const stdoutMessages =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
225
|
+
const stdoutMessages = result.stdout.map((item) => typeof item === "string" ? item : item.toString());
|
|
226
|
+
const stderrMessages = result.stderr.map((item) => typeof item === "string" ? item : item.toString());
|
|
227
|
+
const maxWorkers = this.config.workers;
|
|
228
|
+
let mappedWorkerId = result.workerIndex === -1
|
|
229
|
+
? -1
|
|
230
|
+
: (result.workerIndex % (maxWorkers > 0 ? maxWorkers : 1)) + 1;
|
|
231
|
+
const testSpecificData = {
|
|
232
|
+
workerId: mappedWorkerId,
|
|
233
|
+
totalWorkers: maxWorkers,
|
|
234
|
+
configFile: this.config.configFile,
|
|
235
|
+
metadata: this.config.metadata
|
|
236
|
+
? JSON.stringify(this.config.metadata)
|
|
237
|
+
: undefined,
|
|
238
|
+
};
|
|
194
239
|
const pulseResult = {
|
|
195
|
-
id:
|
|
240
|
+
id: test.id,
|
|
196
241
|
runId: "TBD",
|
|
197
242
|
name: test.titlePath().join(" > "),
|
|
198
|
-
suiteName: (project === null || project === void 0 ? void 0 : project.name) || ((
|
|
243
|
+
suiteName: (project === null || project === void 0 ? void 0 : project.name) || ((_e = this.config.projects[0]) === null || _e === void 0 ? void 0 : _e.name) || "Default Suite",
|
|
199
244
|
status: testStatus,
|
|
200
245
|
duration: result.duration,
|
|
201
246
|
startTime: startTime,
|
|
202
247
|
endTime: endTime,
|
|
203
|
-
browser:
|
|
248
|
+
browser: browserDetails,
|
|
204
249
|
retries: result.retry,
|
|
205
|
-
steps: ((
|
|
206
|
-
errorMessage: (
|
|
207
|
-
stackTrace: (
|
|
250
|
+
steps: ((_f = result.steps) === null || _f === void 0 ? void 0 : _f.length) ? await processAllSteps(result.steps) : [],
|
|
251
|
+
errorMessage: (_g = result.error) === null || _g === void 0 ? void 0 : _g.message,
|
|
252
|
+
stackTrace: (_h = result.error) === null || _h === void 0 ? void 0 : _h.stack,
|
|
208
253
|
codeSnippet: codeSnippet,
|
|
209
254
|
tags: test.tags.map((tag) => tag.startsWith("@") ? tag.substring(1) : tag),
|
|
210
255
|
screenshots: [],
|
|
211
|
-
videoPath:
|
|
256
|
+
videoPath: [],
|
|
212
257
|
tracePath: undefined,
|
|
258
|
+
attachments: [],
|
|
213
259
|
stdout: stdoutMessages.length > 0 ? stdoutMessages : undefined,
|
|
214
260
|
stderr: stderrMessages.length > 0 ? stderrMessages : undefined,
|
|
261
|
+
...testSpecificData,
|
|
215
262
|
};
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
263
|
+
// --- CORRECTED ATTACHMENT PROCESSING LOGIC ---
|
|
264
|
+
for (const [index, attachment] of result.attachments.entries()) {
|
|
265
|
+
if (!attachment.path)
|
|
266
|
+
continue;
|
|
267
|
+
try {
|
|
268
|
+
// Create a sanitized, unique folder name for this specific test
|
|
269
|
+
const testSubfolder = test.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
270
|
+
// Sanitize the original attachment name to create a safe filename
|
|
271
|
+
const safeAttachmentName = path
|
|
272
|
+
.basename(attachment.path)
|
|
273
|
+
.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
274
|
+
// Create a unique filename to prevent collisions, especially in retries
|
|
275
|
+
const uniqueFileName = `${index}-${Date.now()}-${safeAttachmentName}`;
|
|
276
|
+
// This is the relative path that will be stored in the JSON report
|
|
277
|
+
const relativeDestPath = path.join(ATTACHMENTS_SUBDIR, testSubfolder, uniqueFileName);
|
|
278
|
+
// This is the absolute path used for the actual file system operation
|
|
279
|
+
const absoluteDestPath = path.join(this.outputDir, relativeDestPath);
|
|
280
|
+
// Ensure the unique, test-specific attachment directory exists
|
|
281
|
+
await this._ensureDirExists(path.dirname(absoluteDestPath));
|
|
282
|
+
await fs.copyFile(attachment.path, absoluteDestPath);
|
|
283
|
+
// Categorize the attachment based on its content type
|
|
284
|
+
if (attachment.contentType.startsWith("image/")) {
|
|
285
|
+
(_j = pulseResult.screenshots) === null || _j === void 0 ? void 0 : _j.push(relativeDestPath);
|
|
286
|
+
}
|
|
287
|
+
else if (attachment.contentType.startsWith("video/")) {
|
|
288
|
+
(_k = pulseResult.videoPath) === null || _k === void 0 ? void 0 : _k.push(relativeDestPath);
|
|
289
|
+
}
|
|
290
|
+
else if (attachment.name === "trace") {
|
|
291
|
+
pulseResult.tracePath = relativeDestPath;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
(_l = pulseResult.attachments) === null || _l === void 0 ? void 0 : _l.push({
|
|
295
|
+
name: attachment.name, // The original, human-readable name
|
|
296
|
+
path: relativeDestPath, // The safe, relative path for linking
|
|
297
|
+
contentType: attachment.contentType,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
console.error(`Pulse Reporter: Failed to process attachment "${attachment.name}" for test ${pulseResult.name}. Error: ${err.message}`);
|
|
303
|
+
}
|
|
221
304
|
}
|
|
222
|
-
const existingTestIndex = this.results.findIndex((r) => r.id ===
|
|
305
|
+
const existingTestIndex = this.results.findIndex((r) => r.id === test.id);
|
|
223
306
|
if (existingTestIndex !== -1) {
|
|
224
307
|
if (pulseResult.retries >= this.results[existingTestIndex].retries) {
|
|
225
308
|
this.results[existingTestIndex] = pulseResult;
|
|
@@ -236,6 +319,20 @@ class PlaywrightPulseReporter {
|
|
|
236
319
|
console.error(error.stack);
|
|
237
320
|
}
|
|
238
321
|
}
|
|
322
|
+
_getEnvDetails() {
|
|
323
|
+
return {
|
|
324
|
+
host: os.hostname(),
|
|
325
|
+
os: `${os.platform()} ${os.release()}`,
|
|
326
|
+
cpu: {
|
|
327
|
+
model: os.cpus()[0] ? os.cpus()[0].model : "N/A",
|
|
328
|
+
cores: os.cpus().length,
|
|
329
|
+
},
|
|
330
|
+
memory: `${(os.totalmem() / 1024 ** 3).toFixed(2)}GB`,
|
|
331
|
+
node: process.version,
|
|
332
|
+
v8: process.versions.v8,
|
|
333
|
+
cwd: process.cwd(),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
239
336
|
async _writeShardResults() {
|
|
240
337
|
if (this.shardIndex === undefined) {
|
|
241
338
|
return;
|
|
@@ -322,14 +419,14 @@ class PlaywrightPulseReporter {
|
|
|
322
419
|
}
|
|
323
420
|
}
|
|
324
421
|
async onEnd(result) {
|
|
325
|
-
var _a, _b, _c;
|
|
326
422
|
if (this.shardIndex !== undefined) {
|
|
327
423
|
await this._writeShardResults();
|
|
328
424
|
return;
|
|
329
425
|
}
|
|
330
426
|
const runEndTime = Date.now();
|
|
331
427
|
const duration = runEndTime - this.runStartTime;
|
|
332
|
-
const runId = `run-${this.runStartTime}
|
|
428
|
+
const runId = `run-${this.runStartTime}-581d5ad8-ce75-4ca5-94a6-ed29c466c815`;
|
|
429
|
+
const environmentDetails = this._getEnvDetails();
|
|
333
430
|
const runData = {
|
|
334
431
|
id: runId,
|
|
335
432
|
timestamp: new Date(this.runStartTime),
|
|
@@ -338,10 +435,14 @@ class PlaywrightPulseReporter {
|
|
|
338
435
|
failed: 0,
|
|
339
436
|
skipped: 0,
|
|
340
437
|
duration,
|
|
438
|
+
environment: environmentDetails,
|
|
341
439
|
};
|
|
342
|
-
let finalReport = undefined;
|
|
440
|
+
let finalReport = undefined;
|
|
343
441
|
if (this.isSharded) {
|
|
344
442
|
finalReport = await this._mergeShardResults(runData);
|
|
443
|
+
if (finalReport && finalReport.run && !finalReport.run.environment) {
|
|
444
|
+
finalReport.run.environment = environmentDetails;
|
|
445
|
+
}
|
|
345
446
|
}
|
|
346
447
|
else {
|
|
347
448
|
this.results.forEach((r) => (r.runId = runId));
|
|
@@ -366,66 +467,8 @@ class PlaywrightPulseReporter {
|
|
|
366
467
|
}
|
|
367
468
|
if (!finalReport) {
|
|
368
469
|
console.error("PlaywrightPulseReporter: CRITICAL - finalReport object was not generated. Cannot create summary.");
|
|
369
|
-
const errorSummary = `
|
|
370
|
-
PlaywrightPulseReporter: Run Finished
|
|
371
|
-
-----------------------------------------
|
|
372
|
-
Overall Status: ERROR (Report data missing)
|
|
373
|
-
Total Tests: N/A
|
|
374
|
-
Passed: N/A
|
|
375
|
-
Failed: N/A
|
|
376
|
-
Skipped: N/A
|
|
377
|
-
Duration: N/A
|
|
378
|
-
-----------------------------------------`;
|
|
379
|
-
if (this.printsToStdio()) {
|
|
380
|
-
console.log(errorSummary);
|
|
381
|
-
}
|
|
382
|
-
const errorReport = {
|
|
383
|
-
run: {
|
|
384
|
-
id: runId,
|
|
385
|
-
timestamp: new Date(this.runStartTime),
|
|
386
|
-
totalTests: 0,
|
|
387
|
-
passed: 0,
|
|
388
|
-
failed: 0,
|
|
389
|
-
skipped: 0,
|
|
390
|
-
duration: duration,
|
|
391
|
-
},
|
|
392
|
-
results: [],
|
|
393
|
-
metadata: {
|
|
394
|
-
generatedAt: new Date().toISOString(),
|
|
395
|
-
},
|
|
396
|
-
};
|
|
397
|
-
const finalOutputPathOnError = path.join(this.outputDir, this.baseOutputFile);
|
|
398
|
-
try {
|
|
399
|
-
await this._ensureDirExists(this.outputDir);
|
|
400
|
-
await fs.writeFile(finalOutputPathOnError, JSON.stringify(errorReport, null, 2));
|
|
401
|
-
console.warn(`PlaywrightPulseReporter: Wrote an error report to ${finalOutputPathOnError} as finalReport was missing.`);
|
|
402
|
-
}
|
|
403
|
-
catch (writeError) {
|
|
404
|
-
console.error(`PlaywrightPulseReporter: Failed to write error report: ${writeError.message}`);
|
|
405
|
-
}
|
|
406
470
|
return;
|
|
407
471
|
}
|
|
408
|
-
const reportRunData = finalReport.run;
|
|
409
|
-
const finalRunStatus = ((_a = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed) !== null && _a !== void 0 ? _a : 0) > 0
|
|
410
|
-
? "failed"
|
|
411
|
-
: ((_b = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) !== null && _b !== void 0 ? _b : 0) === 0 && result.status !== "passed"
|
|
412
|
-
? result.status === "interrupted"
|
|
413
|
-
? "interrupted"
|
|
414
|
-
: "no tests or error"
|
|
415
|
-
: "passed";
|
|
416
|
-
const summary = `
|
|
417
|
-
PlaywrightPulseReporter: Run Finished
|
|
418
|
-
-----------------------------------------
|
|
419
|
-
Overall Status: ${finalRunStatus.toUpperCase()}
|
|
420
|
-
Total Tests: ${(reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) || 0}
|
|
421
|
-
Passed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.passed}
|
|
422
|
-
Failed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed}
|
|
423
|
-
Skipped: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.skipped}
|
|
424
|
-
Duration: ${(((_c = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.duration) !== null && _c !== void 0 ? _c : 0) / 1000).toFixed(2)}s
|
|
425
|
-
-----------------------------------------`;
|
|
426
|
-
if (this.printsToStdio()) {
|
|
427
|
-
console.log(summary);
|
|
428
|
-
}
|
|
429
472
|
const finalOutputPath = path.join(this.outputDir, this.baseOutputFile);
|
|
430
473
|
try {
|
|
431
474
|
await this._ensureDirExists(this.outputDir);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -32,10 +32,19 @@ export interface TestResult {
|
|
|
32
32
|
runId: string;
|
|
33
33
|
browser: string;
|
|
34
34
|
screenshots?: string[];
|
|
35
|
-
videoPath?: string;
|
|
35
|
+
videoPath?: string[];
|
|
36
36
|
tracePath?: string;
|
|
37
|
+
attachments?: {
|
|
38
|
+
name: string;
|
|
39
|
+
path: string;
|
|
40
|
+
contentType: string;
|
|
41
|
+
}[];
|
|
37
42
|
stdout?: string[];
|
|
38
43
|
stderr?: string[];
|
|
44
|
+
workerId?: number;
|
|
45
|
+
totalWorkers?: number;
|
|
46
|
+
configFile?: string;
|
|
47
|
+
metadata?: string;
|
|
39
48
|
}
|
|
40
49
|
export interface TestRun {
|
|
41
50
|
id: string;
|
|
@@ -45,6 +54,7 @@ export interface TestRun {
|
|
|
45
54
|
failed: number;
|
|
46
55
|
skipped: number;
|
|
47
56
|
duration: number;
|
|
57
|
+
environment?: EnvDetails;
|
|
48
58
|
}
|
|
49
59
|
export interface TrendDataPoint {
|
|
50
60
|
date: string;
|
|
@@ -63,3 +73,15 @@ export interface PlaywrightPulseReporterOptions {
|
|
|
63
73
|
outputDir?: string;
|
|
64
74
|
base64Images?: boolean;
|
|
65
75
|
}
|
|
76
|
+
export interface EnvDetails {
|
|
77
|
+
host: string;
|
|
78
|
+
os: string;
|
|
79
|
+
cpu: {
|
|
80
|
+
model: string;
|
|
81
|
+
cores: number;
|
|
82
|
+
};
|
|
83
|
+
memory: string;
|
|
84
|
+
node: string;
|
|
85
|
+
v8: string;
|
|
86
|
+
cwd: string;
|
|
87
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arghajit/playwright-pulse-report",
|
|
3
3
|
"author": "Arghajit Singha",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.3",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
|
+
"homepage": "https://playwright-pulse-report.netlify.app/",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"playwright",
|
|
8
9
|
"reporter",
|
|
@@ -11,10 +12,13 @@
|
|
|
11
12
|
"reporting",
|
|
12
13
|
"nextjs",
|
|
13
14
|
"playwright-pulse",
|
|
15
|
+
"playwright-pulse-report",
|
|
14
16
|
"report",
|
|
15
17
|
"email-report",
|
|
16
18
|
"send-report",
|
|
17
|
-
"email"
|
|
19
|
+
"email",
|
|
20
|
+
"playwright-report",
|
|
21
|
+
"pulse"
|
|
18
22
|
],
|
|
19
23
|
"main": "dist/reporter/index.js",
|
|
20
24
|
"types": "dist/reporter/index.d.ts",
|
|
@@ -26,9 +30,11 @@
|
|
|
26
30
|
"license": "MIT",
|
|
27
31
|
"bin": {
|
|
28
32
|
"generate-pulse-report": "./scripts/generate-static-report.mjs",
|
|
33
|
+
"generate-report": "./scripts/generate-report.mjs",
|
|
29
34
|
"merge-pulse-report": "./scripts/merge-pulse-report.js",
|
|
30
|
-
"send-email": "./scripts/sendReport.
|
|
31
|
-
"generate-trend": "./scripts/generate-trend.mjs"
|
|
35
|
+
"send-email": "./scripts/sendReport.mjs",
|
|
36
|
+
"generate-trend": "./scripts/generate-trend.mjs",
|
|
37
|
+
"generate-email-report": "./scripts/generate-email-report.mjs"
|
|
32
38
|
},
|
|
33
39
|
"exports": {
|
|
34
40
|
".": {
|
|
@@ -37,78 +43,37 @@
|
|
|
37
43
|
}
|
|
38
44
|
},
|
|
39
45
|
"scripts": {
|
|
40
|
-
"dev": "next dev --turbopack -p 9002",
|
|
41
|
-
"genkit:dev": "genkit start -- tsx src/ai/dev.ts",
|
|
42
|
-
"genkit:watch": "genkit start -- tsx --watch src/ai/dev.ts",
|
|
43
46
|
"build:reporter": "tsc -p tsconfig.reporter.json",
|
|
44
|
-
"build:next": "next build",
|
|
45
|
-
"build": "npm run build:reporter && npm run build:next",
|
|
46
|
-
"start": "next start",
|
|
47
|
-
"lint": "next lint",
|
|
48
47
|
"typecheck": "tsc --noEmit",
|
|
49
48
|
"prepublishOnly": "npm run build:reporter",
|
|
50
49
|
"report:static": "node ./scripts/generate-static-report.mjs",
|
|
50
|
+
"report:generate": "node ./scripts/generate-report.mjs",
|
|
51
51
|
"report:merge": "node ./scripts/merge-pulse-report.js",
|
|
52
|
-
"report:email": "node ./scripts/sendReport.
|
|
52
|
+
"report:email": "node ./scripts/sendReport.mjs",
|
|
53
|
+
"report:minify": "node ./scripts/generate-email-report.mjs",
|
|
54
|
+
"generate-trend": "node ./scripts/generate-trend.mjs"
|
|
53
55
|
},
|
|
54
56
|
"dependencies": {
|
|
55
|
-
"@genkit-ai/googleai": "^1.6.2",
|
|
56
|
-
"@genkit-ai/next": "^1.6.2",
|
|
57
|
-
"@hookform/resolvers": "^4.1.3",
|
|
58
|
-
"@radix-ui/react-accordion": "^1.2.3",
|
|
59
|
-
"@radix-ui/react-alert-dialog": "^1.1.6",
|
|
60
|
-
"@radix-ui/react-avatar": "^1.1.3",
|
|
61
|
-
"@radix-ui/react-checkbox": "^1.1.4",
|
|
62
|
-
"@radix-ui/react-dialog": "^1.1.6",
|
|
63
|
-
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
|
64
|
-
"@radix-ui/react-label": "^2.1.2",
|
|
65
|
-
"@radix-ui/react-menubar": "^1.1.6",
|
|
66
|
-
"@radix-ui/react-popover": "^1.1.6",
|
|
67
|
-
"@radix-ui/react-progress": "^1.1.2",
|
|
68
|
-
"@radix-ui/react-radio-group": "^1.2.3",
|
|
69
|
-
"@radix-ui/react-scroll-area": "^1.2.3",
|
|
70
|
-
"@radix-ui/react-select": "^2.1.6",
|
|
71
|
-
"@radix-ui/react-separator": "^1.1.2",
|
|
72
|
-
"@radix-ui/react-slider": "^1.2.3",
|
|
73
|
-
"@radix-ui/react-slot": "^1.1.2",
|
|
74
|
-
"@radix-ui/react-switch": "^1.1.3",
|
|
75
|
-
"@radix-ui/react-tabs": "^1.1.3",
|
|
76
|
-
"@radix-ui/react-toast": "^1.2.6",
|
|
77
|
-
"@radix-ui/react-tooltip": "^1.1.8",
|
|
78
|
-
"@tanstack-query-firebase/react": "^1.0.5",
|
|
79
|
-
"@tanstack/react-query": "^5.66.0",
|
|
80
57
|
"archiver": "^7.0.1",
|
|
81
58
|
"class-variance-authority": "^0.7.1",
|
|
82
59
|
"clsx": "^2.1.1",
|
|
83
60
|
"d3": "^7.9.0",
|
|
84
61
|
"date-fns": "^3.6.0",
|
|
85
62
|
"dotenv": "^16.5.0",
|
|
86
|
-
"firebase": "^11.3.0",
|
|
87
|
-
"genkit": "^1.6.2",
|
|
88
63
|
"highcharts": "^12.2.0",
|
|
89
64
|
"jsdom": "^26.1.0",
|
|
90
65
|
"lucide-react": "^0.475.0",
|
|
91
|
-
"
|
|
66
|
+
"node-fetch": "^3.3.2",
|
|
92
67
|
"nodemailer": "^7.0.3",
|
|
93
68
|
"patch-package": "^8.0.0",
|
|
94
|
-
"react": "^18.3.1",
|
|
95
|
-
"react-day-picker": "^8.10.1",
|
|
96
|
-
"react-dom": "^18.3.1",
|
|
97
|
-
"react-hook-form": "^7.54.2",
|
|
98
69
|
"recharts": "^2.15.1",
|
|
99
|
-
"
|
|
100
|
-
"tailwindcss-animate": "^1.0.7",
|
|
70
|
+
"ua-parser-js": "^2.0.3",
|
|
101
71
|
"zod": "^3.24.2"
|
|
102
72
|
},
|
|
103
73
|
"devDependencies": {
|
|
104
74
|
"@types/node": "^20",
|
|
105
|
-
"@types/
|
|
106
|
-
"@types/react-dom": "^18",
|
|
75
|
+
"@types/ua-parser-js": "^0.7.39",
|
|
107
76
|
"eslint": "9.25.1",
|
|
108
|
-
"eslint-config-next": "15.3.1",
|
|
109
|
-
"genkit-cli": "^1.6.1",
|
|
110
|
-
"postcss": "^8",
|
|
111
|
-
"tailwindcss": "^3.4.1",
|
|
112
77
|
"typescript": "^5"
|
|
113
78
|
},
|
|
114
79
|
"engines": {
|