playwright-slack-report-burak 3.0.32 ā 3.0.33
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/src/ResultsParser.js +35 -370
- package/package.json +1 -1
|
@@ -9,9 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const axios = require('axios');
|
|
12
|
-
const { exec
|
|
13
|
-
const { promisify } = require('util');
|
|
14
|
-
const execAsync = promisify(exec);
|
|
12
|
+
const { exec } = require('child_process');
|
|
15
13
|
let AdmZip;
|
|
16
14
|
try {
|
|
17
15
|
AdmZip = require('adm-zip');
|
|
@@ -20,18 +18,6 @@ try {
|
|
|
20
18
|
AdmZip = null;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
// Get package version
|
|
24
|
-
let packageVersion = 'unknown';
|
|
25
|
-
try {
|
|
26
|
-
const packageJsonPath = path.join(__dirname, '../../package.json');
|
|
27
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
28
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
29
|
-
packageVersion = packageJson.version || 'unknown';
|
|
30
|
-
}
|
|
31
|
-
} catch (e) {
|
|
32
|
-
// Version detection failed, use default
|
|
33
|
-
}
|
|
34
|
-
|
|
35
21
|
class ResultsParser {
|
|
36
22
|
result;
|
|
37
23
|
separateFlakyTests;
|
|
@@ -45,77 +31,6 @@ class ResultsParser {
|
|
|
45
31
|
constructor(options = { separateFlakyTests: false }) {
|
|
46
32
|
this.result = [];
|
|
47
33
|
this.separateFlakyTests = options.separateFlakyTests;
|
|
48
|
-
// Log package version
|
|
49
|
-
console.log(`š¦ [ResultsParser] playwright-slack-report-burak v${packageVersion}`);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Recursively print directory tree structure
|
|
53
|
-
* @param {string} dirPath - Directory path to print
|
|
54
|
-
* @param {string} prefix - Prefix for tree visualization
|
|
55
|
-
* @param {number} maxDepth - Maximum depth to traverse (default: 5)
|
|
56
|
-
*/
|
|
57
|
-
printDirectoryTree(dirPath, prefix = '', maxDepth = 5) {
|
|
58
|
-
if (maxDepth <= 0) return;
|
|
59
|
-
if (!fs.existsSync(dirPath)) {
|
|
60
|
-
console.log(`${prefix}${path.basename(dirPath)}/ (does not exist)`);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const stats = fs.statSync(dirPath);
|
|
66
|
-
if (!stats.isDirectory()) {
|
|
67
|
-
const size = stats.size;
|
|
68
|
-
const sizeStr = size > 1024 ? `${(size / 1024).toFixed(2)}KB` : `${size}B`;
|
|
69
|
-
console.log(`${prefix}${path.basename(dirPath)} (${sizeStr})`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const dirName = path.basename(dirPath) || dirPath;
|
|
74
|
-
console.log(`${prefix}${dirName}/`);
|
|
75
|
-
|
|
76
|
-
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
77
|
-
entries.sort((a, b) => {
|
|
78
|
-
if (a.isDirectory() && !b.isDirectory()) return -1;
|
|
79
|
-
if (!a.isDirectory() && b.isDirectory()) return 1;
|
|
80
|
-
return a.name.localeCompare(b.name);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
entries.forEach((entry, index) => {
|
|
84
|
-
const isLast = index === entries.length - 1;
|
|
85
|
-
const newPrefix = prefix + (isLast ? 'āāā ' : 'āāā ');
|
|
86
|
-
const nextPrefix = prefix + (isLast ? ' ' : 'ā ');
|
|
87
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
88
|
-
|
|
89
|
-
if (entry.isDirectory()) {
|
|
90
|
-
this.printDirectoryTree(fullPath, nextPrefix, maxDepth - 1);
|
|
91
|
-
} else {
|
|
92
|
-
try {
|
|
93
|
-
const fileStats = fs.statSync(fullPath);
|
|
94
|
-
const size = fileStats.size;
|
|
95
|
-
const sizeStr = size > 1024 * 1024
|
|
96
|
-
? `${(size / (1024 * 1024)).toFixed(2)}MB`
|
|
97
|
-
: size > 1024
|
|
98
|
-
? `${(size / 1024).toFixed(2)}KB`
|
|
99
|
-
: `${size}B`;
|
|
100
|
-
console.log(`${newPrefix}${entry.name} (${sizeStr})`);
|
|
101
|
-
} catch (err) {
|
|
102
|
-
console.log(`${newPrefix}${entry.name} (error reading)`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.log(`${prefix}${path.basename(dirPath)}/ (error: ${error.message})`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Update shard information after detection (e.g., from GitHub API)
|
|
113
|
-
* @param {number} shardIndex - The current shard index (1-based, shard 1 is aggregator)
|
|
114
|
-
* @param {number} totalShardCount - The total number of shards
|
|
115
|
-
*/
|
|
116
|
-
updateShardInfo(shardIndex, totalShardCount) {
|
|
117
|
-
this.shardIndex = shardIndex;
|
|
118
|
-
this.totalShardCount = totalShardCount;
|
|
119
34
|
}
|
|
120
35
|
async getParsedResults() {
|
|
121
36
|
const summary = {
|
|
@@ -174,9 +89,11 @@ class ResultsParser {
|
|
|
174
89
|
|
|
175
90
|
if (this.shardIndex === 1 && this.totalShardCount > 1) {
|
|
176
91
|
if (process.env.CI) {
|
|
92
|
+
console.log('Fetching all artifacts...');
|
|
177
93
|
await this.fetchAllArtifacts();
|
|
178
94
|
} else {
|
|
179
95
|
while (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
|
|
96
|
+
console.log('Waiting for all both to exist...');
|
|
180
97
|
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second
|
|
181
98
|
}
|
|
182
99
|
}
|
|
@@ -184,7 +101,6 @@ class ResultsParser {
|
|
|
184
101
|
|
|
185
102
|
if (this.shardIndex === 1 && this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
|
|
186
103
|
// Merge all node summaries into the final summary
|
|
187
|
-
// Loop from 1 to totalShardCount (1-based indexing)
|
|
188
104
|
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
189
105
|
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
190
106
|
const fileToRead = nodeSummaryFile;
|
|
@@ -221,7 +137,7 @@ class ResultsParser {
|
|
|
221
137
|
}
|
|
222
138
|
}
|
|
223
139
|
|
|
224
|
-
|
|
140
|
+
this.mergeReports();
|
|
225
141
|
}
|
|
226
142
|
return summary;
|
|
227
143
|
}
|
|
@@ -400,7 +316,6 @@ class ResultsParser {
|
|
|
400
316
|
console.log('Checking if all node summary files exist...');
|
|
401
317
|
const summariesDir = path.join('./', 'playwright-report');
|
|
402
318
|
|
|
403
|
-
// Check files from 1 to totalShardCount (1-based indexing)
|
|
404
319
|
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
405
320
|
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
406
321
|
if (!fs.existsSync(nodeSummaryFile)) {
|
|
@@ -414,7 +329,6 @@ class ResultsParser {
|
|
|
414
329
|
console.log('Checking if all blob zips exist...');
|
|
415
330
|
const summariesDir = path.join('./', 'playwright-report');
|
|
416
331
|
|
|
417
|
-
// Check files from 1 to totalShardCount (1-based indexing)
|
|
418
332
|
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
419
333
|
const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
|
|
420
334
|
if (!fs.existsSync(blobZipFile)) {
|
|
@@ -426,55 +340,15 @@ class ResultsParser {
|
|
|
426
340
|
|
|
427
341
|
async fetchAllArtifacts() {
|
|
428
342
|
const summariesDir = path.join('./', 'playwright-report');
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (i === 1) continue; // Skip shard 1 (we are shard 1)
|
|
439
|
-
console.log(`Shard 1: Fetching artifacts from shard ${i}...`);
|
|
440
|
-
await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
|
|
441
|
-
await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// After fetching, verify all files exist and wait if needed
|
|
445
|
-
let retryCount = 0;
|
|
446
|
-
const maxRetries = 60; // Wait up to 10 minutes (60 * 10 seconds)
|
|
447
|
-
|
|
448
|
-
while ((!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) && retryCount < maxRetries) {
|
|
449
|
-
console.log(`Shard 1: Waiting for all artifacts to be available (attempt ${retryCount + 1}/${maxRetries})...`);
|
|
450
|
-
|
|
451
|
-
// Re-fetch any missing artifacts
|
|
452
|
-
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
453
|
-
if (i === 1) continue; // Skip shard 1 (we are shard 1)
|
|
454
|
-
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
455
|
-
const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
|
|
456
|
-
|
|
457
|
-
if (!fs.existsSync(nodeSummaryFile)) {
|
|
458
|
-
console.log(`Shard 1: Re-fetching missing node_summary_${i}.json...`);
|
|
459
|
-
await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (!fs.existsSync(blobZipFile)) {
|
|
463
|
-
console.log(`Shard 1: Re-fetching missing blob-report-node-${i}.zip...`);
|
|
464
|
-
await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
retryCount++;
|
|
469
|
-
if (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
|
|
470
|
-
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds before retry
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
if (this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
|
|
475
|
-
console.log(`Shard 1: Successfully fetched all artifacts from ${this.totalShardCount - 1} other shard(s).`);
|
|
476
|
-
} else {
|
|
477
|
-
console.warn(`Shard 1: Warning - Some artifacts may still be missing after ${maxRetries} attempts.`);
|
|
343
|
+
while (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
|
|
344
|
+
console.log('Waiting for all blob zips to exist...');
|
|
345
|
+
if (!fs.existsSync(summariesDir)) {
|
|
346
|
+
fs.mkdirSync(summariesDir, { recursive: true });
|
|
347
|
+
}
|
|
348
|
+
for (let i = 2; i <= this.totalShardCount; i++) {
|
|
349
|
+
await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
|
|
350
|
+
await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
|
|
351
|
+
}
|
|
478
352
|
}
|
|
479
353
|
}
|
|
480
354
|
|
|
@@ -486,20 +360,9 @@ class ResultsParser {
|
|
|
486
360
|
async fetchArtifactFromGitHubActions(i, file, filePath) {
|
|
487
361
|
const githubToken = process.env.SAFETYWINGTEST_GITHUB_TOKEN;
|
|
488
362
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
489
|
-
const runId = process.env.GITHUB_RUN_ID;
|
|
490
|
-
|
|
491
|
-
if (!githubToken || !repo) {
|
|
492
|
-
console.error('GitHub Actions: Missing SAFETYWINGTEST_GITHUB_TOKEN or GITHUB_REPOSITORY');
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// GitHub Actions artifact API endpoint
|
|
497
363
|
const githubApiUrl = `https://api.github.com/repos/${repo}/actions/artifacts`;
|
|
498
364
|
|
|
499
|
-
// Try multiple artifact naming patterns
|
|
500
|
-
// 1. html-report-{i} (1-based workflow style)
|
|
501
|
-
// 2. blob-report-node-{i} (direct blob reports)
|
|
502
|
-
// 3. test-results-{i} (alternative naming)
|
|
365
|
+
// Try multiple artifact naming patterns
|
|
503
366
|
const artifactNamePatterns = [
|
|
504
367
|
`html-report-${i}`,
|
|
505
368
|
`blob-report-node-${i}`,
|
|
@@ -527,10 +390,7 @@ class ResultsParser {
|
|
|
527
390
|
a.name.includes(`shard-${i}`) ||
|
|
528
391
|
a.name.includes(`node-${i}`)
|
|
529
392
|
);
|
|
530
|
-
if (artifact)
|
|
531
|
-
console.log(`Found artifact: ${artifact.name} (matched pattern: ${pattern})`);
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
393
|
+
if (artifact) break;
|
|
534
394
|
}
|
|
535
395
|
|
|
536
396
|
if (artifact && artifact.archive_download_url) {
|
|
@@ -550,69 +410,15 @@ class ResultsParser {
|
|
|
550
410
|
|
|
551
411
|
// Extract ZIP and find the specific file
|
|
552
412
|
const zip = new AdmZip(downloadResponse.data);
|
|
553
|
-
|
|
554
|
-
// Try direct file match first
|
|
555
|
-
let zipEntry = zip.getEntry(file);
|
|
556
|
-
|
|
557
|
-
// If not found, try common path variations
|
|
558
|
-
if (!zipEntry) {
|
|
559
|
-
const possiblePaths = [
|
|
560
|
-
file,
|
|
561
|
-
`playwright-report/${file}`,
|
|
562
|
-
`html-report-${i}/${file}`,
|
|
563
|
-
`html-report-${i}/playwright-report/${file}`,
|
|
564
|
-
];
|
|
565
|
-
for (const possiblePath of possiblePaths) {
|
|
566
|
-
zipEntry = zip.getEntry(possiblePath);
|
|
567
|
-
if (zipEntry) break;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
413
|
+
const zipEntry = zip.getEntry(file) || zip.getEntry(`playwright-report/${file}`);
|
|
570
414
|
|
|
571
415
|
if (zipEntry) {
|
|
572
416
|
fs.writeFileSync(filePath, zipEntry.getData());
|
|
573
|
-
console.log(`Successfully fetched file ${file} from
|
|
417
|
+
console.log(`Successfully fetched file ${file} from shard ${i}`);
|
|
574
418
|
break;
|
|
575
419
|
} else {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
zip.extractAllTo(extractPath, true);
|
|
579
|
-
|
|
580
|
-
// Look for the file recursively
|
|
581
|
-
const searchInDir = (dir, targetFile) => {
|
|
582
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
583
|
-
for (const entry of entries) {
|
|
584
|
-
const fullPath = path.join(dir, entry.name);
|
|
585
|
-
if (entry.isDirectory()) {
|
|
586
|
-
const found = searchInDir(fullPath, targetFile);
|
|
587
|
-
if (found) return found;
|
|
588
|
-
} else {
|
|
589
|
-
// Check exact match
|
|
590
|
-
if (entry.name === targetFile) {
|
|
591
|
-
return fullPath;
|
|
592
|
-
}
|
|
593
|
-
// Check if ends with target file
|
|
594
|
-
if (entry.name.endsWith(targetFile)) {
|
|
595
|
-
return fullPath;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
return null;
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
// Try to find the file recursively
|
|
603
|
-
let foundPath = searchInDir(extractPath, file);
|
|
604
|
-
|
|
605
|
-
if (foundPath) {
|
|
606
|
-
fs.copyFileSync(foundPath, filePath);
|
|
607
|
-
console.log(`Successfully fetched file ${file} from GitHub Actions shard ${i} (artifact: ${artifact.name})`);
|
|
608
|
-
// Clean up temp directory
|
|
609
|
-
fs.rmSync(extractPath, { recursive: true, force: true });
|
|
610
|
-
break;
|
|
611
|
-
} else {
|
|
612
|
-
console.warn(`File ${file} not found in artifact ${artifact.name}. Retrying in 10 seconds...`);
|
|
613
|
-
fs.rmSync(extractPath, { recursive: true, force: true });
|
|
614
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
615
|
-
}
|
|
420
|
+
console.warn(`File ${file} not found in artifact ${artifact.name}. Retrying in 10 seconds...`);
|
|
421
|
+
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
616
422
|
}
|
|
617
423
|
} else {
|
|
618
424
|
console.warn(`Artifact not found (tried: ${artifactNamePatterns.join(', ')}). Retrying in 10 seconds...`);
|
|
@@ -620,173 +426,32 @@ class ResultsParser {
|
|
|
620
426
|
}
|
|
621
427
|
} catch (error) {
|
|
622
428
|
if (error.response && error.response.status === 404) {
|
|
623
|
-
console.warn(`
|
|
429
|
+
console.warn(`File ${file} not found. Retrying in 10 seconds...`);
|
|
624
430
|
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
625
431
|
} else {
|
|
626
|
-
console.error(`Failed to fetch
|
|
627
|
-
|
|
432
|
+
console.error(`Failed to fetch file ${file} from shard ${i}!`, error);
|
|
433
|
+
break;
|
|
628
434
|
}
|
|
629
435
|
}
|
|
630
436
|
}
|
|
631
437
|
}
|
|
632
|
-
|
|
438
|
+
mergeReports() {
|
|
439
|
+
let breakMergeWaiter = false;
|
|
633
440
|
try {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
console.log('\nš Initial playwright-report directory structure:');
|
|
645
|
-
if (fs.existsSync(summariesDir)) {
|
|
646
|
-
this.printDirectoryTree(summariesDir);
|
|
647
|
-
} else {
|
|
648
|
-
console.log(' (directory does not exist yet)');
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Create directory for extracted blob reports
|
|
652
|
-
if (!fs.existsSync(blobReportsDir)) {
|
|
653
|
-
fs.mkdirSync(blobReportsDir, { recursive: true });
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// Create directory for merged blob reports output
|
|
657
|
-
if (!fs.existsSync(mergedBlobsDir)) {
|
|
658
|
-
fs.mkdirSync(mergedBlobsDir, { recursive: true });
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// Extract all blob zips to preserve traces
|
|
662
|
-
console.log('\nš¦ Extracting blob reports to preserve traces...');
|
|
663
|
-
let hasBlobReports = false;
|
|
664
|
-
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
665
|
-
const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
|
|
666
|
-
if (fs.existsSync(blobZipFile)) {
|
|
667
|
-
if (!AdmZip) {
|
|
668
|
-
console.warn('adm-zip is required for blob extraction. Falling back to HTML report merge.');
|
|
669
|
-
break;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const zip = new AdmZip(blobZipFile);
|
|
673
|
-
const extractPath = path.join(blobReportsDir, `node-${i}`);
|
|
674
|
-
zip.extractAllTo(extractPath, true);
|
|
675
|
-
console.log(`Extracted blob report from shard ${i}`);
|
|
676
|
-
hasBlobReports = true;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// Show directory structure after extraction
|
|
681
|
-
if (hasBlobReports) {
|
|
682
|
-
console.log('\nš Directory structure after blob extraction:');
|
|
683
|
-
this.printDirectoryTree(summariesDir);
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// Merge blob reports instead of HTML reports to preserve traces
|
|
687
|
-
if (hasBlobReports && fs.existsSync(blobReportsDir) && fs.readdirSync(blobReportsDir).length > 0) {
|
|
688
|
-
console.log('\nš Merging blob reports (preserves traces)...');
|
|
689
|
-
let tempConfigPath = null;
|
|
690
|
-
try {
|
|
691
|
-
// Merge blob reports - use config file to specify output directory
|
|
692
|
-
// This prevents wiping the playwright-report directory
|
|
693
|
-
const blobReportsRelativePath = path.relative(summariesDir, blobReportsDir);
|
|
694
|
-
const mergedBlobsAbsolutePath = path.resolve(mergedBlobsDir);
|
|
695
|
-
console.log(`Merging blob reports from: ${blobReportsRelativePath}`);
|
|
696
|
-
console.log(`Output directory: ${mergedBlobsAbsolutePath}`);
|
|
697
|
-
|
|
698
|
-
// Create temporary config file to specify output folder
|
|
699
|
-
tempConfigPath = path.join(summariesDir, 'merge-config.js');
|
|
700
|
-
const tempConfigAbsolutePath = path.resolve(tempConfigPath);
|
|
701
|
-
// Escape backslashes and single quotes in path for JavaScript string
|
|
702
|
-
const escapedPath = mergedBlobsAbsolutePath.replace(/\\/g, '/').replace(/'/g, "\\'");
|
|
703
|
-
const configContent = `module.exports = {
|
|
704
|
-
reporter: [['html', { outputFolder: '${escapedPath}' }]]
|
|
705
|
-
};`;
|
|
706
|
-
fs.writeFileSync(tempConfigPath, configContent);
|
|
707
|
-
console.log(`Created temporary config file: ${tempConfigAbsolutePath}`);
|
|
708
|
-
console.log(`Config content: ${configContent}`);
|
|
709
|
-
|
|
710
|
-
// Use absolute path for config file to avoid path resolution issues
|
|
711
|
-
const mergeCommand = `npx playwright merge-reports --reporter html --config "${tempConfigAbsolutePath}" "${blobReportsRelativePath}"`;
|
|
712
|
-
console.log(`Executing: ${mergeCommand}`);
|
|
713
|
-
const mergeResult = await execAsync(mergeCommand, { cwd: summariesDir });
|
|
714
|
-
console.log('Merge command output:', mergeResult.stdout);
|
|
715
|
-
if (mergeResult.stderr) {
|
|
716
|
-
console.warn('Merge command stderr:', mergeResult.stderr);
|
|
717
|
-
}
|
|
718
|
-
console.log('Blob reports merged successfully with traces preserved.');
|
|
719
|
-
|
|
720
|
-
// Show directory structure after merge
|
|
721
|
-
console.log('\nš Directory structure after merge:');
|
|
722
|
-
this.printDirectoryTree(summariesDir);
|
|
723
|
-
console.log('\nš Merged blobs directory contents:');
|
|
724
|
-
this.printDirectoryTree(mergedBlobsDir);
|
|
725
|
-
} catch (error) {
|
|
726
|
-
console.warn('Warning: Failed to merge blob reports. Falling back to HTML merge.', error.message);
|
|
727
|
-
if (error.stdout) console.log('Merge stdout:', error.stdout);
|
|
728
|
-
if (error.stderr) console.warn('Merge stderr:', error.stderr);
|
|
729
|
-
|
|
730
|
-
// Show directory structure after failed merge
|
|
731
|
-
console.log('\nš Directory structure after failed merge:');
|
|
732
|
-
this.printDirectoryTree(summariesDir);
|
|
733
|
-
|
|
734
|
-
// Fallback to HTML merge
|
|
735
|
-
execSync(`npx playwright merge-reports --reporter html -c ./playwright-report playwright-report`, { stdio: 'inherit' });
|
|
736
|
-
} finally {
|
|
737
|
-
// Clean up temporary config file
|
|
738
|
-
if (tempConfigPath) {
|
|
739
|
-
const configPathToDelete = fs.existsSync(tempConfigPath) ? tempConfigPath : path.resolve(tempConfigPath);
|
|
740
|
-
if (fs.existsSync(configPathToDelete)) {
|
|
741
|
-
try {
|
|
742
|
-
fs.unlinkSync(configPathToDelete);
|
|
743
|
-
console.log(`Cleaned up temporary config file: ${configPathToDelete}`);
|
|
744
|
-
} catch (cleanupError) {
|
|
745
|
-
console.warn(`Warning: Failed to clean up temp config file: ${cleanupError.message}`);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
441
|
+
// Execute the command to merge reports
|
|
442
|
+
exec(`npx playwright merge-reports --reporter html -c ./playwright-report playwright-report`);
|
|
443
|
+
// Wait until index.html exists
|
|
444
|
+
while (!fs.existsSync(path.join('./playwright-report', 'index.html'))) {
|
|
445
|
+
console.log('Waiting 2 seconds for merged html report to be generated...');
|
|
446
|
+
const currentTime = new Date().getTime();
|
|
447
|
+
breakMergeWaiter = false;
|
|
448
|
+
while (!breakMergeWaiter) {
|
|
449
|
+
if(new Date().getTime() - currentTime > 2000) {
|
|
450
|
+
breakMergeWaiter = true;
|
|
748
451
|
}
|
|
749
452
|
}
|
|
750
|
-
} else {
|
|
751
|
-
// Fallback to HTML merge if no blob reports found
|
|
752
|
-
console.log('No blob reports found, falling back to HTML report merge...');
|
|
753
|
-
execSync(`npx playwright merge-reports --reporter html -c ./playwright-report playwright-report`, { stdio: 'inherit' });
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// Wait until index.html exists in mergedBlobsDir (with timeout)
|
|
757
|
-
const maxWaitTime = 60000; // 60 seconds max wait
|
|
758
|
-
const startWaitTime = new Date().getTime();
|
|
759
|
-
const indexHtmlPath = path.join(mergedBlobsDir, 'index.html');
|
|
760
|
-
|
|
761
|
-
console.log('\nā³ Waiting for merged HTML report to be generated...');
|
|
762
|
-
while (!fs.existsSync(indexHtmlPath)) {
|
|
763
|
-
const elapsed = new Date().getTime() - startWaitTime;
|
|
764
|
-
if (elapsed > maxWaitTime) {
|
|
765
|
-
console.warn(`\nā±ļø Timeout: index.html not found in ${mergedBlobsDir} after ${maxWaitTime}ms`);
|
|
766
|
-
console.log(`Checking if directory exists: ${fs.existsSync(mergedBlobsDir)}`);
|
|
767
|
-
if (fs.existsSync(mergedBlobsDir)) {
|
|
768
|
-
console.log('\nš Full directory tree at timeout:');
|
|
769
|
-
this.printDirectoryTree(summariesDir);
|
|
770
|
-
console.log('\nš Merged blobs directory detailed contents:');
|
|
771
|
-
this.printDirectoryTree(mergedBlobsDir);
|
|
772
|
-
} else {
|
|
773
|
-
console.log('Merged blobs directory does not exist!');
|
|
774
|
-
}
|
|
775
|
-
break;
|
|
776
|
-
}
|
|
777
|
-
console.log(`Waiting for merged html report to be generated... (${Math.round(elapsed/1000)}s elapsed)`);
|
|
778
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
if (fs.existsSync(indexHtmlPath)) {
|
|
782
|
-
console.log('\nā
Reports merged successfully.');
|
|
783
|
-
console.log('\nš Final directory structure:');
|
|
784
|
-
this.printDirectoryTree(summariesDir);
|
|
785
|
-
} else {
|
|
786
|
-
console.warn('\nā ļø Warning: Merged report index.html not found, but continuing...');
|
|
787
|
-
console.log('\nš Final directory structure:');
|
|
788
|
-
this.printDirectoryTree(summariesDir);
|
|
789
453
|
}
|
|
454
|
+
console.log('Reports merged successfully.');
|
|
790
455
|
} catch (error) {
|
|
791
456
|
// Log a warning instead of throwing an error
|
|
792
457
|
console.warn('Warning: Failed to merge reports. This may not affect the overall process.', error.message);
|
package/package.json
CHANGED