playwright-slack-report-burak 3.0.32 → 3.0.34

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.
@@ -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, execSync } = require('child_process');
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,17 +18,9 @@ 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
- }
21
+ const SUMMARIES_DIR = path.join('./', 'playwright-report');
22
+ const NODE_ARTIFACTS_DIR = path.join(SUMMARIES_DIR, 'nodeArtifacts');
23
+ const FINAL_OUTPUT_DIR = path.join(SUMMARIES_DIR, 'finalOutput');
34
24
 
35
25
  class ResultsParser {
36
26
  result;
@@ -45,77 +35,6 @@ class ResultsParser {
45
35
  constructor(options = { separateFlakyTests: false }) {
46
36
  this.result = [];
47
37
  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
38
  }
120
39
  async getParsedResults() {
121
40
  const summary = {
@@ -135,17 +54,15 @@ class ResultsParser {
135
54
  }*/
136
55
 
137
56
  // Define the directory to store node summaries
138
- const summariesDir = path.join('./', 'playwright-report');
139
-
140
- if (!fs.existsSync(summariesDir)) {
141
- fs.mkdirSync(summariesDir, { recursive: true });
57
+ if (!fs.existsSync(SUMMARIES_DIR)) {
58
+ fs.mkdirSync(SUMMARIES_DIR, { recursive: true });
142
59
  }
143
60
 
144
61
  // Determine the current node index
145
62
  const currentNodeIndex = this.shardIndex;
146
63
 
147
64
  // Define the file for the current node's summary
148
- const nodeSummaryFile = path.join(summariesDir, `node_summary_${currentNodeIndex}.json`);
65
+ const nodeSummaryFile = path.join(SUMMARIES_DIR, `node_summary_${currentNodeIndex}.json`);
149
66
 
150
67
  const totalTestCasesForNode = this.result.reduce((acc, suite) => acc + suite.testSuite.tests.length, 0);
151
68
 
@@ -174,9 +91,11 @@ class ResultsParser {
174
91
 
175
92
  if (this.shardIndex === 1 && this.totalShardCount > 1) {
176
93
  if (process.env.CI) {
94
+ console.log('Fetching all artifacts...');
177
95
  await this.fetchAllArtifacts();
178
96
  } else {
179
97
  while (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
98
+ console.log('Waiting for all both to exist...');
180
99
  await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second
181
100
  }
182
101
  }
@@ -184,9 +103,8 @@ class ResultsParser {
184
103
 
185
104
  if (this.shardIndex === 1 && this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
186
105
  // Merge all node summaries into the final summary
187
- // Loop from 1 to totalShardCount (1-based indexing)
188
106
  for (let i = 1; i <= this.totalShardCount; i++) {
189
- const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
107
+ const nodeSummaryFile = path.join(SUMMARIES_DIR, `node_summary_${i}.json`);
190
108
  const fileToRead = nodeSummaryFile;
191
109
 
192
110
  if (fs.existsSync(fileToRead)) {
@@ -221,7 +139,7 @@ class ResultsParser {
221
139
  }
222
140
  }
223
141
 
224
- await this.mergeReports();
142
+ this.mergeReports();
225
143
  }
226
144
  return summary;
227
145
  }
@@ -398,11 +316,9 @@ class ResultsParser {
398
316
  }*/
399
317
  allNodeSummaryFilesExist() {
400
318
  console.log('Checking if all node summary files exist...');
401
- const summariesDir = path.join('./', 'playwright-report');
402
319
 
403
- // Check files from 1 to totalShardCount (1-based indexing)
404
320
  for (let i = 1; i <= this.totalShardCount; i++) {
405
- const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
321
+ const nodeSummaryFile = path.join(SUMMARIES_DIR, `node_summary_${i}.json`);
406
322
  if (!fs.existsSync(nodeSummaryFile)) {
407
323
  return false;
408
324
  }
@@ -412,11 +328,9 @@ class ResultsParser {
412
328
 
413
329
  allBlobZipsExist() {
414
330
  console.log('Checking if all blob zips exist...');
415
- 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
- const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
333
+ const blobZipFile = path.join(NODE_ARTIFACTS_DIR, `blob-report-node-${i}.zip`);
420
334
  if (!fs.existsSync(blobZipFile)) {
421
335
  return false;
422
336
  }
@@ -425,81 +339,63 @@ class ResultsParser {
425
339
  }
426
340
 
427
341
  async fetchAllArtifacts() {
428
- const summariesDir = path.join('./', 'playwright-report');
429
- if (!fs.existsSync(summariesDir)) {
430
- fs.mkdirSync(summariesDir, { recursive: true });
342
+ // Ensure playwright-report directory exists
343
+ if (!fs.existsSync(SUMMARIES_DIR)) {
344
+ fs.mkdirSync(SUMMARIES_DIR, { recursive: true });
431
345
  }
432
346
 
433
- console.log(`Shard 1: Waiting for artifacts from ${this.totalShardCount - 1} other shard(s)...`);
434
-
435
- // Fetch artifacts for all shards except shard 1 (since we're shard 1)
436
- // We need to fetch from shards 2, 3, 4, ... (all except shard 1, using 1-based indexing)
437
- for (let i = 1; i <= this.totalShardCount; i++) {
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);
347
+ // Create nodeArtifacts directory under playwright-report
348
+ if (!fs.existsSync(NODE_ARTIFACTS_DIR)) {
349
+ fs.mkdirSync(NODE_ARTIFACTS_DIR, { recursive: true });
442
350
  }
443
351
 
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)
352
+ // Copy artifacts from node 1 to nodeArtifacts
353
+ // Check multiple potential locations for node 1's blob file
354
+ const possibleNode1BlobSources = [
355
+ path.join(SUMMARIES_DIR, 'blob-report-node-1.zip'),
356
+ path.join('./', 'blob-report-node-1.zip'),
357
+ path.join(SUMMARIES_DIR, 'blob-report-1.zip'),
358
+ ];
447
359
 
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
360
+ const node1BlobDest = path.join(NODE_ARTIFACTS_DIR, 'blob-report-node-1.zip');
361
+ let node1BlobCopied = false;
362
+
363
+ for (const source of possibleNode1BlobSources) {
364
+ if (fs.existsSync(source)) {
365
+ fs.copyFileSync(source, node1BlobDest);
366
+ console.log(`Copied ${source} to nodeArtifacts`);
367
+ node1BlobCopied = true;
368
+ break;
471
369
  }
472
370
  }
473
371
 
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.`);
372
+ if (!node1BlobCopied) {
373
+ console.warn('Warning: blob-report-node-1.zip not found in expected locations');
374
+ }
375
+
376
+ while (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
377
+ console.log('Waiting for all blob zips to exist...');
378
+ if (!fs.existsSync(SUMMARIES_DIR)) {
379
+ fs.mkdirSync(SUMMARIES_DIR, { recursive: true });
380
+ }
381
+ for (let i = 2; i <= this.totalShardCount; i++) {
382
+ await this.fetchArtifact(i, `node_summary_${i}.json`, SUMMARIES_DIR);
383
+ await this.fetchArtifact(i, `blob-report-node-${i}.zip`, NODE_ARTIFACTS_DIR);
384
+ }
478
385
  }
479
386
  }
480
387
 
481
- async fetchArtifact(i, file, summariesDir) {
482
- const filePath = path.join(summariesDir, file);
388
+ async fetchArtifact(i, file, targetDir) {
389
+ const filePath = path.join(targetDir, file);
483
390
  await this.fetchArtifactFromGitHubActions(i, file, filePath);
484
391
  }
485
392
 
486
393
  async fetchArtifactFromGitHubActions(i, file, filePath) {
487
394
  const githubToken = process.env.SAFETYWINGTEST_GITHUB_TOKEN;
488
395
  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
396
  const githubApiUrl = `https://api.github.com/repos/${repo}/actions/artifacts`;
498
397
 
499
- // Try multiple artifact naming patterns (all 1-based):
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)
398
+ // Try multiple artifact naming patterns
503
399
  const artifactNamePatterns = [
504
400
  `html-report-${i}`,
505
401
  `blob-report-node-${i}`,
@@ -527,10 +423,7 @@ class ResultsParser {
527
423
  a.name.includes(`shard-${i}`) ||
528
424
  a.name.includes(`node-${i}`)
529
425
  );
530
- if (artifact) {
531
- console.log(`Found artifact: ${artifact.name} (matched pattern: ${pattern})`);
532
- break;
533
- }
426
+ if (artifact) break;
534
427
  }
535
428
 
536
429
  if (artifact && artifact.archive_download_url) {
@@ -550,69 +443,15 @@ class ResultsParser {
550
443
 
551
444
  // Extract ZIP and find the specific file
552
445
  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
- }
446
+ const zipEntry = zip.getEntry(file) || zip.getEntry(`playwright-report/${file}`);
570
447
 
571
448
  if (zipEntry) {
572
449
  fs.writeFileSync(filePath, zipEntry.getData());
573
- console.log(`Successfully fetched file ${file} from GitHub Actions shard ${i} (artifact: ${artifact.name})`);
450
+ console.log(`Successfully fetched file ${file} from shard ${i}`);
574
451
  break;
575
452
  } else {
576
- // If file not found in ZIP root, extract and search recursively
577
- const extractPath = path.join(path.dirname(filePath), `temp-artifact-${i}`);
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
- }
453
+ console.warn(`File ${file} not found in artifact ${artifact.name}. Retrying in 10 seconds...`);
454
+ await new Promise(resolve => setTimeout(resolve, 10000));
616
455
  }
617
456
  } else {
618
457
  console.warn(`Artifact not found (tried: ${artifactNamePatterns.join(', ')}). Retrying in 10 seconds...`);
@@ -620,177 +459,125 @@ class ResultsParser {
620
459
  }
621
460
  } catch (error) {
622
461
  if (error.response && error.response.status === 404) {
623
- console.warn(`Artifact not found. Retrying in 10 seconds...`);
462
+ console.warn(`File ${file} not found. Retrying in 10 seconds...`);
624
463
  await new Promise(resolve => setTimeout(resolve, 10000));
625
464
  } else {
626
- console.error(`Failed to fetch artifact from GitHub Actions shard ${i}!`, error.message);
627
- await new Promise(resolve => setTimeout(resolve, 10000));
465
+ console.error(`Failed to fetch file ${file} from shard ${i}!`, error);
466
+ break;
628
467
  }
629
468
  }
630
469
  }
631
470
  }
632
- async mergeReports() {
471
+ mergeReports() {
472
+ let breakMergeWaiter = false;
633
473
  try {
634
- const summariesDir = path.join('./', 'playwright-report');
635
- const blobReportsDir = path.join(summariesDir, 'blob-reports');
636
- const mergedBlobsDir = path.join(summariesDir, 'mergedBlobsDir');
637
-
638
- console.log('\n=== Starting merge process ===');
639
- console.log(`Summaries directory: ${path.resolve(summariesDir)}`);
640
- console.log(`Blob reports directory: ${path.resolve(blobReportsDir)}`);
641
- console.log(`Merged blobs directory: ${path.resolve(mergedBlobsDir)}`);
642
-
643
- // Show initial directory structure
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)');
474
+ // Ensure playwright-report directory exists
475
+ if (!fs.existsSync(SUMMARIES_DIR)) {
476
+ fs.mkdirSync(SUMMARIES_DIR, { recursive: true });
649
477
  }
650
478
 
651
- // Create directory for extracted blob reports
652
- if (!fs.existsSync(blobReportsDir)) {
653
- fs.mkdirSync(blobReportsDir, { recursive: true });
479
+ // Create finalOutput directory under playwright-report
480
+ if (!fs.existsSync(FINAL_OUTPUT_DIR)) {
481
+ fs.mkdirSync(FINAL_OUTPUT_DIR, { recursive: true });
654
482
  }
655
483
 
656
- // Create directory for merged blob reports output
657
- if (!fs.existsSync(mergedBlobsDir)) {
658
- fs.mkdirSync(mergedBlobsDir, { recursive: true });
484
+ // Extract blob files before merging (Playwright merge-reports expects extracted blob directories)
485
+ // We'll extract them temporarily for merging, then extract again for resource copying
486
+ const tempMergeDir = path.join(NODE_ARTIFACTS_DIR, 'temp-merge');
487
+ if (!fs.existsSync(tempMergeDir)) {
488
+ fs.mkdirSync(tempMergeDir, { recursive: true });
659
489
  }
660
490
 
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);
491
+ // Extract all blob zip files to temp directory for merging
492
+ if (!AdmZip) {
493
+ console.error('adm-zip is required for blob extraction. Please install it: npm install adm-zip');
494
+ return;
684
495
  }
685
496
 
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)) {
497
+ for (let i = 1; i <= this.totalShardCount; i++) {
498
+ const blobZipFile = path.join(NODE_ARTIFACTS_DIR, `blob-report-node-${i}.zip`);
499
+ if (fs.existsSync(blobZipFile)) {
741
500
  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}`);
501
+ const zip = new AdmZip(blobZipFile);
502
+ zip.extractAllTo(tempMergeDir, true);
503
+ console.log(`Extracted blob-report-node-${i}.zip for merging`);
504
+ } catch (error) {
505
+ console.warn(`Failed to extract blob-report-node-${i}.zip for merging:`, error.message);
746
506
  }
747
- }
748
507
  }
749
- }
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
508
  }
755
509
 
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');
510
+ // Execute the command to merge reports FROM tempMergeDir INTO finalOutput
511
+ exec(`npx playwright merge-reports --reporter html ${tempMergeDir} ${FINAL_OUTPUT_DIR}`);
760
512
 
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!');
513
+ // Wait until index.html exists in finalOutput
514
+ while (!fs.existsSync(path.join(FINAL_OUTPUT_DIR, 'index.html'))) {
515
+ console.log('Waiting 2 seconds for merged html report to be generated...');
516
+ const currentTime = new Date().getTime();
517
+ breakMergeWaiter = false;
518
+ while (!breakMergeWaiter) {
519
+ if(new Date().getTime() - currentTime > 2000) {
520
+ breakMergeWaiter = true;
774
521
  }
775
- break;
776
522
  }
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
523
  }
524
+ console.log('Reports merged successfully.');
780
525
 
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
- }
526
+ // Once merge is complete, unzip all blobs in nodeArtifacts into separate folders
527
+ this.unzipBlobsAndCopyResources(NODE_ARTIFACTS_DIR, FINAL_OUTPUT_DIR);
790
528
  } catch (error) {
791
529
  // Log a warning instead of throwing an error
792
530
  console.warn('Warning: Failed to merge reports. This may not affect the overall process.', error.message);
793
531
  }
794
532
  }
533
+
534
+ unzipBlobsAndCopyResources(nodeArtifactsDir, finalOutputDir) {
535
+ if (!AdmZip) {
536
+ console.error('adm-zip is required for blob extraction. Please install it: npm install adm-zip');
537
+ return;
538
+ }
539
+
540
+ // Unzip all blob files in nodeArtifacts into separate folders
541
+ for (let i = 1; i <= this.totalShardCount; i++) {
542
+ const blobZipFile = path.join(nodeArtifactsDir, `blob-report-node-${i}.zip`);
543
+ if (fs.existsSync(blobZipFile)) {
544
+ const extractDir = path.join(nodeArtifactsDir, `node-${i}`);
545
+ if (!fs.existsSync(extractDir)) {
546
+ fs.mkdirSync(extractDir, { recursive: true });
547
+ }
548
+
549
+ try {
550
+ const zip = new AdmZip(blobZipFile);
551
+ zip.extractAllTo(extractDir, true);
552
+ console.log(`Extracted blob-report-node-${i}.zip to ${extractDir}`);
553
+
554
+ // Check if this folder contains a "resources" folder with zip files
555
+ const resourcesDir = path.join(extractDir, 'resources');
556
+ if (fs.existsSync(resourcesDir) && fs.statSync(resourcesDir).isDirectory()) {
557
+ const files = fs.readdirSync(resourcesDir);
558
+ const zipFiles = files.filter(file => file.endsWith('.zip'));
559
+
560
+ if (zipFiles.length > 0) {
561
+ // Copy the resources folder to finalOutput
562
+ const finalResourcesDir = path.join(finalOutputDir, 'resources');
563
+ if (!fs.existsSync(finalResourcesDir)) {
564
+ fs.mkdirSync(finalResourcesDir, { recursive: true });
565
+ }
566
+
567
+ // Copy each zip file to finalOutput/resources
568
+ for (const zipFile of zipFiles) {
569
+ const sourceFile = path.join(resourcesDir, zipFile);
570
+ const destFile = path.join(finalResourcesDir, zipFile);
571
+ fs.copyFileSync(sourceFile, destFile);
572
+ console.log(`Copied ${zipFile} to finalOutput/resources`);
573
+ }
574
+ }
575
+ }
576
+ } catch (error) {
577
+ console.warn(`Failed to extract or process blob-report-node-${i}.zip:`, error.message);
578
+ }
579
+ }
580
+ }
581
+ }
795
582
  }
796
583
  exports.default = ResultsParser;
package/package.json CHANGED
@@ -32,7 +32,7 @@
32
32
  "lint-fix": "npx eslint . --ext .ts --fix"
33
33
  },
34
34
  "name": "playwright-slack-report-burak",
35
- "version": "3.0.32",
35
+ "version": "3.0.34",
36
36
  "main": "index.js",
37
37
  "types": "dist/index.d.ts",
38
38
  "author": "Burak B. <burak.boluk@hotmail.com>",