@arghajit/dummy 0.1.0-beta-21 → 0.1.0-beta-23
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.
|
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.PlaywrightPulseReporter = void 0;
|
|
37
37
|
const fs = __importStar(require("fs/promises"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const fsSync = __importStar(require("fs"));
|
|
40
39
|
const crypto_1 = require("crypto");
|
|
41
40
|
const ua_parser_js_1 = require("ua-parser-js");
|
|
42
41
|
const os = __importStar(require("os"));
|
|
@@ -61,6 +60,7 @@ const convertStatus = (status, testCase) => {
|
|
|
61
60
|
};
|
|
62
61
|
const TEMP_SHARD_FILE_PREFIX = ".pulse-shard-results-";
|
|
63
62
|
const ATTACHMENTS_SUBDIR = "attachments";
|
|
63
|
+
const INDIVIDUAL_REPORTS_SUBDIR = "pulse-results";
|
|
64
64
|
class PlaywrightPulseReporter {
|
|
65
65
|
constructor(options = {}) {
|
|
66
66
|
var _a, _b, _c;
|
|
@@ -72,7 +72,7 @@ class PlaywrightPulseReporter {
|
|
|
72
72
|
this.baseOutputFile = (_a = options.outputFile) !== null && _a !== void 0 ? _a : this.baseOutputFile;
|
|
73
73
|
this.outputDir = (_b = options.outputDir) !== null && _b !== void 0 ? _b : "pulse-report";
|
|
74
74
|
this.attachmentsDir = path.join(this.outputDir, ATTACHMENTS_SUBDIR);
|
|
75
|
-
this.resetOnEachRun = (_c = options.resetOnEachRun) !== null && _c !== void 0 ? _c :
|
|
75
|
+
this.resetOnEachRun = (_c = options.resetOnEachRun) !== null && _c !== void 0 ? _c : true;
|
|
76
76
|
}
|
|
77
77
|
printsToStdio() {
|
|
78
78
|
return this.shardIndex === undefined || this.shardIndex === 0;
|
|
@@ -96,7 +96,7 @@ class PlaywrightPulseReporter {
|
|
|
96
96
|
: undefined;
|
|
97
97
|
this._ensureDirExists(this.outputDir)
|
|
98
98
|
.then(() => {
|
|
99
|
-
if (this.
|
|
99
|
+
if (this.printsToStdio()) {
|
|
100
100
|
console.log(`PlaywrightPulseReporter: Starting test run with ${suite.allTests().length} tests${this.isSharded ? ` across ${totalShards} shards` : ""}. Pulse outputting to ${this.outputDir}`);
|
|
101
101
|
if (this.shardIndex === undefined ||
|
|
102
102
|
(this.isSharded && this.shardIndex === 0)) {
|
|
@@ -262,27 +262,19 @@ class PlaywrightPulseReporter {
|
|
|
262
262
|
stderr: stderrMessages.length > 0 ? stderrMessages : undefined,
|
|
263
263
|
...testSpecificData,
|
|
264
264
|
};
|
|
265
|
-
// --- CORRECTED ATTACHMENT PROCESSING LOGIC ---
|
|
266
265
|
for (const [index, attachment] of result.attachments.entries()) {
|
|
267
266
|
if (!attachment.path)
|
|
268
267
|
continue;
|
|
269
268
|
try {
|
|
270
|
-
// Create a sanitized, unique folder name for this specific test
|
|
271
269
|
const testSubfolder = test.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
272
|
-
// Sanitize the original attachment name to create a safe filename
|
|
273
270
|
const safeAttachmentName = path
|
|
274
271
|
.basename(attachment.path)
|
|
275
272
|
.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
276
|
-
// Create a unique filename to prevent collisions, especially in retries
|
|
277
273
|
const uniqueFileName = `${index}-${Date.now()}-${safeAttachmentName}`;
|
|
278
|
-
// This is the relative path that will be stored in the JSON report
|
|
279
274
|
const relativeDestPath = path.join(ATTACHMENTS_SUBDIR, testSubfolder, uniqueFileName);
|
|
280
|
-
// This is the absolute path used for the actual file system operation
|
|
281
275
|
const absoluteDestPath = path.join(this.outputDir, relativeDestPath);
|
|
282
|
-
// Ensure the unique, test-specific attachment directory exists
|
|
283
276
|
await this._ensureDirExists(path.dirname(absoluteDestPath));
|
|
284
277
|
await fs.copyFile(attachment.path, absoluteDestPath);
|
|
285
|
-
// Categorize the attachment based on its content type
|
|
286
278
|
if (attachment.contentType.startsWith("image/")) {
|
|
287
279
|
(_j = pulseResult.screenshots) === null || _j === void 0 ? void 0 : _j.push(relativeDestPath);
|
|
288
280
|
}
|
|
@@ -294,8 +286,8 @@ class PlaywrightPulseReporter {
|
|
|
294
286
|
}
|
|
295
287
|
else {
|
|
296
288
|
(_l = pulseResult.attachments) === null || _l === void 0 ? void 0 : _l.push({
|
|
297
|
-
name: attachment.name,
|
|
298
|
-
path: relativeDestPath,
|
|
289
|
+
name: attachment.name,
|
|
290
|
+
path: relativeDestPath,
|
|
299
291
|
contentType: attachment.contentType,
|
|
300
292
|
});
|
|
301
293
|
}
|
|
@@ -442,9 +434,6 @@ class PlaywrightPulseReporter {
|
|
|
442
434
|
let finalReport = undefined;
|
|
443
435
|
if (this.isSharded) {
|
|
444
436
|
finalReport = await this._mergeShardResults(runData);
|
|
445
|
-
if (finalReport && finalReport.run && !finalReport.run.environment) {
|
|
446
|
-
finalReport.run.environment = environmentDetails;
|
|
447
|
-
}
|
|
448
437
|
}
|
|
449
438
|
else {
|
|
450
439
|
this.results.forEach((r) => (r.runId = runId));
|
|
@@ -452,18 +441,9 @@ class PlaywrightPulseReporter {
|
|
|
452
441
|
runData.failed = this.results.filter((r) => r.status === "failed").length;
|
|
453
442
|
runData.skipped = this.results.filter((r) => r.status === "skipped").length;
|
|
454
443
|
runData.totalTests = this.results.length;
|
|
455
|
-
const reviveDates = (key, value) => {
|
|
456
|
-
const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;
|
|
457
|
-
if (typeof value === "string" && isoDateRegex.test(value)) {
|
|
458
|
-
const date = new Date(value);
|
|
459
|
-
return !isNaN(date.getTime()) ? date : value;
|
|
460
|
-
}
|
|
461
|
-
return value;
|
|
462
|
-
};
|
|
463
|
-
const properlyTypedResults = JSON.parse(JSON.stringify(this.results), reviveDates);
|
|
464
444
|
finalReport = {
|
|
465
445
|
run: runData,
|
|
466
|
-
results:
|
|
446
|
+
results: this.results,
|
|
467
447
|
metadata: { generatedAt: new Date().toISOString() },
|
|
468
448
|
};
|
|
469
449
|
}
|
|
@@ -471,17 +451,18 @@ class PlaywrightPulseReporter {
|
|
|
471
451
|
console.error("PlaywrightPulseReporter: CRITICAL - finalReport object was not generated. Cannot create summary.");
|
|
472
452
|
return;
|
|
473
453
|
}
|
|
474
|
-
|
|
454
|
+
const jsonReplacer = (key, value) => {
|
|
455
|
+
if (value instanceof Date)
|
|
456
|
+
return value.toISOString();
|
|
457
|
+
if (typeof value === "bigint")
|
|
458
|
+
return value.toString();
|
|
459
|
+
return value;
|
|
460
|
+
};
|
|
461
|
+
if (this.resetOnEachRun) {
|
|
475
462
|
const finalOutputPath = path.join(this.outputDir, this.baseOutputFile);
|
|
476
463
|
try {
|
|
477
464
|
await this._ensureDirExists(this.outputDir);
|
|
478
|
-
await fs.writeFile(finalOutputPath, JSON.stringify(finalReport,
|
|
479
|
-
if (value instanceof Date)
|
|
480
|
-
return value.toISOString();
|
|
481
|
-
if (typeof value === "bigint")
|
|
482
|
-
return value.toString();
|
|
483
|
-
return value;
|
|
484
|
-
}, 2));
|
|
465
|
+
await fs.writeFile(finalOutputPath, JSON.stringify(finalReport, jsonReplacer, 2));
|
|
485
466
|
if (this.printsToStdio()) {
|
|
486
467
|
console.log(`PlaywrightPulseReporter: JSON report written to ${finalOutputPath}`);
|
|
487
468
|
}
|
|
@@ -489,100 +470,110 @@ class PlaywrightPulseReporter {
|
|
|
489
470
|
catch (error) {
|
|
490
471
|
console.error(`Pulse Reporter: Failed to write final JSON report to ${finalOutputPath}. Error: ${error.message}`);
|
|
491
472
|
}
|
|
492
|
-
finally {
|
|
493
|
-
if (this.isSharded) {
|
|
494
|
-
await this._cleanupTemporaryFiles();
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
473
|
}
|
|
498
474
|
else {
|
|
499
|
-
|
|
500
|
-
const
|
|
475
|
+
// Logic for appending/merging reports
|
|
476
|
+
const pulseResultsDir = path.join(this.outputDir, INDIVIDUAL_REPORTS_SUBDIR);
|
|
477
|
+
const individualReportPath = path.join(pulseResultsDir, `playwright-pulse-report-${Date.now()}.json`);
|
|
501
478
|
try {
|
|
502
|
-
await this._ensureDirExists(
|
|
503
|
-
await fs.writeFile(
|
|
504
|
-
if (value instanceof Date)
|
|
505
|
-
return value.toISOString();
|
|
506
|
-
if (typeof value === "bigint")
|
|
507
|
-
return value.toString();
|
|
508
|
-
return value;
|
|
509
|
-
}, 2));
|
|
479
|
+
await this._ensureDirExists(pulseResultsDir);
|
|
480
|
+
await fs.writeFile(individualReportPath, JSON.stringify(finalReport, jsonReplacer, 2));
|
|
510
481
|
if (this.printsToStdio()) {
|
|
511
|
-
console.log(`PlaywrightPulseReporter:
|
|
482
|
+
console.log(`PlaywrightPulseReporter: Individual run report for merging written to ${individualReportPath}`);
|
|
512
483
|
}
|
|
484
|
+
await this._mergeAllRunReports();
|
|
513
485
|
}
|
|
514
486
|
catch (error) {
|
|
515
|
-
console.error(`Pulse Reporter: Failed to write
|
|
487
|
+
console.error(`Pulse Reporter: Failed to write or merge report. Error: ${error.message}`);
|
|
516
488
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
489
|
+
}
|
|
490
|
+
if (this.isSharded) {
|
|
491
|
+
await this._cleanupTemporaryFiles();
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async _mergeAllRunReports() {
|
|
495
|
+
const pulseResultsDir = path.join(this.outputDir, INDIVIDUAL_REPORTS_SUBDIR);
|
|
496
|
+
const finalOutputPath = path.join(this.outputDir, this.baseOutputFile);
|
|
497
|
+
let reportFiles;
|
|
498
|
+
try {
|
|
499
|
+
const allFiles = await fs.readdir(pulseResultsDir);
|
|
500
|
+
reportFiles = allFiles.filter((file) => file.startsWith("playwright-pulse-report-") && file.endsWith(".json"));
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
if (error.code === "ENOENT") {
|
|
504
|
+
if (this.printsToStdio()) {
|
|
505
|
+
console.log(`Pulse Reporter: No individual reports directory found at ${pulseResultsDir}. Skipping merge.`);
|
|
520
506
|
}
|
|
507
|
+
return;
|
|
521
508
|
}
|
|
509
|
+
console.error(`Pulse Reporter: Error reading report directory ${pulseResultsDir}:`, error);
|
|
510
|
+
return;
|
|
522
511
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
.filter((file) => file.startsWith("playwright-pulse-report-") && file.endsWith(".json"));
|
|
533
|
-
}
|
|
534
|
-
function mergeReports(files) {
|
|
535
|
-
var _a;
|
|
536
|
-
let combinedRun = {
|
|
512
|
+
if (reportFiles.length === 0) {
|
|
513
|
+
if (this.printsToStdio()) {
|
|
514
|
+
console.log("Pulse Reporter: No matching JSON report files found to merge.");
|
|
515
|
+
}
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const combinedRun = {
|
|
519
|
+
id: `merged-${Date.now()}`,
|
|
520
|
+
timestamp: new Date(0),
|
|
537
521
|
totalTests: 0,
|
|
538
522
|
passed: 0,
|
|
539
523
|
failed: 0,
|
|
540
524
|
skipped: 0,
|
|
541
525
|
duration: 0,
|
|
542
|
-
environment:
|
|
526
|
+
environment: undefined,
|
|
543
527
|
};
|
|
544
|
-
|
|
545
|
-
let latestTimestamp =
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
528
|
+
const allResults = [];
|
|
529
|
+
let latestTimestamp = new Date(0);
|
|
530
|
+
for (const file of reportFiles) {
|
|
531
|
+
const filePath = path.join(pulseResultsDir, file);
|
|
532
|
+
try {
|
|
533
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
534
|
+
const json = JSON.parse(content);
|
|
535
|
+
if (json.run) {
|
|
536
|
+
combinedRun.totalTests += json.run.totalTests || 0;
|
|
537
|
+
combinedRun.passed += json.run.passed || 0;
|
|
538
|
+
combinedRun.failed += json.run.failed || 0;
|
|
539
|
+
combinedRun.skipped += json.run.skipped || 0;
|
|
540
|
+
combinedRun.duration += json.run.duration || 0;
|
|
541
|
+
const runTimestamp = new Date(json.run.timestamp);
|
|
542
|
+
if (runTimestamp > latestTimestamp) {
|
|
543
|
+
latestTimestamp = runTimestamp;
|
|
544
|
+
combinedRun.environment = json.run.environment || undefined;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (json.results) {
|
|
548
|
+
allResults.push(...json.results);
|
|
549
|
+
}
|
|
559
550
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
run:
|
|
567
|
-
|
|
568
|
-
timestamp: latestTimestamp,
|
|
569
|
-
...combinedRun,
|
|
570
|
-
},
|
|
571
|
-
results: combinedResults,
|
|
551
|
+
catch (err) {
|
|
552
|
+
console.warn(`Pulse Reporter: Could not parse report file ${filePath}. Skipping. Error: ${err.message}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
combinedRun.timestamp = latestTimestamp;
|
|
556
|
+
const finalReport = {
|
|
557
|
+
run: combinedRun,
|
|
558
|
+
results: allResults,
|
|
572
559
|
metadata: {
|
|
573
|
-
generatedAt:
|
|
560
|
+
generatedAt: new Date().toISOString(),
|
|
574
561
|
},
|
|
575
562
|
};
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
563
|
+
try {
|
|
564
|
+
await fs.writeFile(finalOutputPath, JSON.stringify(finalReport, (key, value) => {
|
|
565
|
+
if (value instanceof Date)
|
|
566
|
+
return value.toISOString();
|
|
567
|
+
return value;
|
|
568
|
+
}, 2));
|
|
569
|
+
if (this.printsToStdio()) {
|
|
570
|
+
console.log(`PlaywrightPulseReporter: ✅ Merged report with ${allResults.length} total results saved to ${finalOutputPath}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (err) {
|
|
574
|
+
console.error(`Pulse Reporter: Failed to write final merged report to ${finalOutputPath}. Error: ${err.message}`);
|
|
575
|
+
}
|
|
583
576
|
}
|
|
584
|
-
const merged = mergeReports(reportFiles);
|
|
585
|
-
fsSync.writeFileSync(path.join(REPORT_DIR, OUTPUT_FILE), JSON.stringify(merged, null, 2));
|
|
586
|
-
console.log(`✅ Merged report saved as ${OUTPUT_FILE}`);
|
|
587
577
|
}
|
|
578
|
+
exports.PlaywrightPulseReporter = PlaywrightPulseReporter;
|
|
588
579
|
exports.default = PlaywrightPulseReporter;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arghajit/dummy",
|
|
3
3
|
"author": "Arghajit Singha",
|
|
4
|
-
"version": "0.1.0-beta-
|
|
4
|
+
"version": "0.1.0-beta-23",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
6
|
"homepage": "https://playwright-pulse-report.netlify.app/",
|
|
7
7
|
"keywords": [
|