playwright-slack-report-burak 3.0.21 → 3.0.22

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.
@@ -33,16 +33,12 @@ try {
33
33
  class ResultsParser {
34
34
  result;
35
35
  separateFlakyTests;
36
- // Handle both 0-based and 1-based shard indexing
37
- // If MATRIX_SHARD is not set, try to infer from workflow (1-based) or default to 0
38
36
  totalShardCount = process.env.TOTAL_SHARDS
39
37
  ? parseInt(process.env.TOTAL_SHARDS, 10)
40
- : (process.env.MATRIX_COUNT ? parseInt(process.env.MATRIX_COUNT, 10) : 1);
38
+ : 1;
41
39
  shardIndex = process.env.SHARD_INDEX !== undefined
42
40
  ? parseInt(process.env.SHARD_INDEX, 10)
43
- : (process.env.MATRIX_SHARD !== undefined
44
- ? parseInt(process.env.MATRIX_SHARD, 10)
45
- : (process.env.MATRIX_INDEX !== undefined ? parseInt(process.env.MATRIX_INDEX, 10) : 0));
41
+ : 1;
46
42
 
47
43
  constructor(options = { separateFlakyTests: false }) {
48
44
  this.result = [];
@@ -438,17 +434,14 @@ class ResultsParser {
438
434
  // GitHub Actions artifact API endpoint
439
435
  const githubApiUrl = `https://api.github.com/repos/${repo}/actions/artifacts`;
440
436
 
441
- // Try multiple artifact naming patterns:
442
- // 1. html-report-{i} (1-based workflow style, i is already 1-based)
443
- // 2. blob-report-node-{i} (direct blob reports, i is 1-based)
444
- // 3. test-results-{i} (alternative naming, i is 1-based)
445
- // Note: i is 1-based internally now, so we use it directly for GitHub Actions artifacts
437
+ // Try multiple artifact naming patterns (all 1-based):
438
+ // 1. html-report-{i} (1-based workflow style)
439
+ // 2. blob-report-node-{i} (direct blob reports)
440
+ // 3. test-results-{i} (alternative naming)
446
441
  const artifactNamePatterns = [
447
- `html-report-${i}`, // 1-based workflow style (i is already 1-based)
448
- `blob-report-node-${i}`, // 1-based direct blob
449
- `html-report-${i - 1}`, // 0-based html-report (fallback)
450
- `blob-report-node-${i - 1}`, // 0-based direct blob (fallback)
451
- `test-results-${i}`, // Alternative naming
442
+ `html-report-${i}`,
443
+ `blob-report-node-${i}`,
444
+ `test-results-${i}`,
452
445
  ];
453
446
 
454
447
  while (true) {
@@ -469,10 +462,8 @@ class ResultsParser {
469
462
  for (const pattern of artifactNamePatterns) {
470
463
  artifact = listResponse.data.artifacts.find(
471
464
  (a) => a.name === pattern ||
472
- a.name.includes(`shard-${i}`) ||
473
- a.name.includes(`shard-${i - 1}`) ||
474
- a.name.includes(`node-${i}`) ||
475
- a.name.includes(`node-${i - 1}`)
465
+ a.name.includes(`shard-${i}`) ||
466
+ a.name.includes(`node-${i}`)
476
467
  );
477
468
  if (artifact) {
478
469
  console.log(`Found artifact: ${artifact.name} (matched pattern: ${pattern})`);
@@ -506,9 +497,8 @@ class ResultsParser {
506
497
  const possiblePaths = [
507
498
  file,
508
499
  `playwright-report/${file}`,
509
- `playwright-report/${file}`,
510
500
  `html-report-${i}/${file}`,
511
- `html-report-${i - 1}/${file}`,
501
+ `html-report-${i}/playwright-report/${file}`,
512
502
  ];
513
503
  for (const possiblePath of possiblePaths) {
514
504
  zipEntry = zip.getEntry(possiblePath);
@@ -526,22 +516,18 @@ class ResultsParser {
526
516
  zip.extractAllTo(extractPath, true);
527
517
 
528
518
  // Look for the file recursively
529
- const searchInDir = (dir, targetFile, alternateTargetFile = null) => {
519
+ const searchInDir = (dir, targetFile) => {
530
520
  const entries = fs.readdirSync(dir, { withFileTypes: true });
531
521
  for (const entry of entries) {
532
522
  const fullPath = path.join(dir, entry.name);
533
523
  if (entry.isDirectory()) {
534
- const found = searchInDir(fullPath, targetFile, alternateTargetFile);
524
+ const found = searchInDir(fullPath, targetFile);
535
525
  if (found) return found;
536
526
  } else {
537
527
  // Check exact match
538
528
  if (entry.name === targetFile) {
539
529
  return fullPath;
540
530
  }
541
- // Check alternate filename (e.g., node_summary_0.json when we need node_summary_1.json)
542
- if (alternateTargetFile && entry.name === alternateTargetFile) {
543
- return fullPath;
544
- }
545
531
  // Check if ends with target file
546
532
  if (entry.name.endsWith(targetFile)) {
547
533
  return fullPath;
@@ -551,45 +537,9 @@ class ResultsParser {
551
537
  return null;
552
538
  };
553
539
 
554
- // Try to find the file, also try with shard index from artifact
540
+ // Try to find the file recursively
555
541
  let foundPath = searchInDir(extractPath, file);
556
542
 
557
- // If file uses index 0 pattern (like node_summary_0.json or blob-report-node-0.zip)
558
- // but we need it for a different shard, try to find any matching pattern
559
- if (!foundPath && (file.includes('_0') || file.includes('-node-0'))) {
560
- // Recursively search for any node_summary or blob-report file
561
- const findAllFiles = (dir, pattern) => {
562
- const results = [];
563
- try {
564
- const entries = fs.readdirSync(dir, { withFileTypes: true });
565
- for (const entry of entries) {
566
- const fullPath = path.join(dir, entry.name);
567
- if (entry.isDirectory()) {
568
- results.push(...findAllFiles(fullPath, pattern));
569
- } else if (entry.name.includes(pattern)) {
570
- results.push(fullPath);
571
- }
572
- }
573
- } catch (e) {
574
- // Ignore errors
575
- }
576
- return results;
577
- };
578
-
579
- // Find any node_summary or blob-report files
580
- const matchingFiles = findAllFiles(extractPath, file.includes('node_summary') ? 'node_summary' : 'blob-report');
581
-
582
- if (matchingFiles.length > 0) {
583
- foundPath = matchingFiles[0];
584
- // Copy to the expected path with correct shard index
585
- fs.copyFileSync(foundPath, filePath);
586
- console.log(`Found and copied file ${path.basename(foundPath)} -> ${file} from artifact ${artifact.name}`);
587
- // Clean up temp directory
588
- fs.rmSync(extractPath, { recursive: true, force: true });
589
- break;
590
- }
591
- }
592
-
593
543
  if (foundPath) {
594
544
  fs.copyFileSync(foundPath, filePath);
595
545
  console.log(`Successfully fetched file ${file} from GitHub Actions shard ${i} (artifact: ${artifact.name})`);
@@ -90,182 +90,6 @@ class SlackReporter {
90
90
  onTestEnd(test, result) {
91
91
  this.resultsParser.addTestResult(test.parent.title, test, this.browsers);
92
92
  }
93
- /**
94
- * Detect GitHub Actions shard information using GitHub API
95
- * Returns { shardIndex: number, totalShards: number } or null if detection fails
96
- */
97
- async detectGitHubActionsShardInfo() {
98
- // Check if we're in GitHub Actions
99
- if (!process.env.GITHUB_ACTIONS || process.env.GITHUB_ACTIONS !== 'true') {
100
- return null;
101
- }
102
- // Try GITHUB_TOKEN first (automatic), then fallback to custom token
103
- const githubToken = process.env.GITHUB_TOKEN || process.env.SAFETYWINGTEST_GITHUB_TOKEN;
104
- const repo = process.env.GITHUB_REPOSITORY;
105
- const runId = process.env.GITHUB_RUN_ID;
106
- const currentJobId = process.env.GITHUB_JOB;
107
- if (!githubToken || !repo || !runId) {
108
- return null;
109
- }
110
- if (!axios) {
111
- return null;
112
- }
113
- try {
114
- // Get workflow run details
115
- const apiUrl = `https://api.github.com/repos/${repo}/actions/runs/${runId}/jobs`;
116
- const response = await axios.get(apiUrl, {
117
- headers: {
118
- 'Accept': 'application/vnd.github+json',
119
- 'Authorization': `Bearer ${githubToken}`,
120
- 'X-GitHub-Api-Version': '2022-11-28'
121
- },
122
- params: {
123
- per_page: 100
124
- }
125
- });
126
- const jobs = response.data.jobs || [];
127
- if (jobs.length === 0) {
128
- return null;
129
- }
130
-
131
- // Helper function to normalize job names by removing shard indicators
132
- // e.g., "Run tests (shard 3/4)" -> "Run tests"
133
- const normalizeJobName = (name) => {
134
- if (!name) return '';
135
- // Remove common matrix patterns: (shard X/Y), (X, Y), [X], etc.
136
- return name
137
- .replace(/\s*\(shard\s+\d+\/\d+\)/gi, '')
138
- .replace(/\s*\(\d+\/\d+\)/g, '')
139
- .replace(/\s*\(\d+,\s*\d+\)/g, '')
140
- .replace(/\s*\[\d+\]/g, '')
141
- .trim();
142
- };
143
-
144
- // Group jobs by normalized name to find matrix jobs
145
- const jobGroups = {};
146
- for (const job of jobs) {
147
- const jobName = job.name || '';
148
- const normalizedName = normalizeJobName(jobName);
149
- if (!jobGroups[normalizedName]) {
150
- jobGroups[normalizedName] = [];
151
- }
152
- jobGroups[normalizedName].push(job);
153
- }
154
-
155
- // Find the job group that contains the current job
156
- let currentJob = null;
157
- let jobGroup = null;
158
-
159
- // Strategy 1: Find the currently running job (status: in_progress or completed recently)
160
- const runningJobs = jobs.filter(j => j.status === 'in_progress' || j.status === 'queued');
161
-
162
- if (runningJobs.length === 1) {
163
- // Perfect - only one job is running, must be us
164
- currentJob = runningJobs[0];
165
- const normalizedName = normalizeJobName(currentJob.name);
166
- jobGroup = jobGroups[normalizedName];
167
- } else if (runningJobs.length > 1) {
168
- // Multiple running jobs - try to match by job ID or name
169
- for (const job of runningJobs) {
170
- // Check if this job's name contains the GITHUB_JOB id
171
- // But be more specific - avoid matching "Generate test matrix" when looking for "test"
172
- const jobIdLower = currentJobId.toLowerCase();
173
- const jobNameLower = (job.name || '').toLowerCase();
174
-
175
- // Match if job name starts with or equals the job ID (more specific)
176
- if (jobNameLower.startsWith(jobIdLower) ||
177
- jobNameLower.includes(`${jobIdLower} `) ||
178
- jobNameLower.includes(`${jobIdLower}(`) ||
179
- jobNameLower === jobIdLower) {
180
- currentJob = job;
181
- const normalizedName = normalizeJobName(job.name);
182
- jobGroup = jobGroups[normalizedName];
183
- break;
184
- }
185
- }
186
-
187
- // Still no match? Take the first running job that looks like a test job
188
- if (!currentJob) {
189
- for (const job of runningJobs) {
190
- if (job.name && (job.name.includes('shard') || job.name.includes('test') || job.name.includes('matrix'))) {
191
- currentJob = job;
192
- const normalizedName = normalizeJobName(job.name);
193
- jobGroup = jobGroups[normalizedName];
194
- break;
195
- }
196
- }
197
- }
198
- }
199
-
200
- // Strategy 2: If no running job found, look at all jobs
201
- if (!currentJob) {
202
- for (const job of jobs) {
203
- const jobIdLower = currentJobId.toLowerCase();
204
- const jobNameLower = (job.name || '').toLowerCase();
205
-
206
- if (jobNameLower.startsWith(jobIdLower) ||
207
- jobNameLower.includes(`${jobIdLower} `) ||
208
- jobNameLower.includes(`${jobIdLower}(`)) {
209
- currentJob = job;
210
- const normalizedName = normalizeJobName(job.name);
211
- jobGroup = jobGroups[normalizedName];
212
- break;
213
- }
214
- }
215
- }
216
-
217
- // Fallback: Use the largest job group (likely the matrix jobs)
218
- if (!jobGroup || jobGroup.length === 0) {
219
- let largestGroup = [];
220
- for (const [, groupJobs] of Object.entries(jobGroups)) {
221
- if (groupJobs.length > largestGroup.length) {
222
- largestGroup = groupJobs;
223
- }
224
- }
225
- jobGroup = largestGroup;
226
- currentJob = jobGroup[0];
227
- }
228
- // Sort jobs by name or ID to get consistent ordering
229
- jobGroup.sort((a, b) => {
230
- if (a.name && b.name) {
231
- return a.name.localeCompare(b.name);
232
- }
233
- return a.id - b.id;
234
- });
235
-
236
- // Find index of current job in the sorted group
237
- const currentJobIndex = jobGroup.findIndex(j => j.id === currentJob?.id || j.name === currentJob?.name);
238
-
239
- // Try to extract shard number from job name (e.g., "shard 3/4" -> index 3)
240
- // GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4), we keep it 1-based internally for shard 1 logic
241
- let shardIndex = currentJobIndex >= 0 ? currentJobIndex : 0;
242
- if (currentJob && currentJob.name) {
243
- const shardMatch = currentJob.name.match(/shard\s+(\d+)\/(\d+)/i);
244
- if (shardMatch) {
245
- const shardNum = parseInt(shardMatch[1], 10); // 1-based from GitHub Actions (1, 2, 3, 4)
246
- const totalFromName = parseInt(shardMatch[2], 10);
247
- // Keep GitHub Actions 1-based indexing (shard 1 -> index 1, shard 2 -> index 2, etc.)
248
- // This allows shard 1 to be the aggregator
249
- shardIndex = shardNum;
250
- }
251
- }
252
-
253
- // If we couldn't extract from name but have job index, convert from 0-based array index to 1-based
254
- // GitHub Actions jobs are numbered starting from 1, so array index 0 = shard 1, index 1 = shard 2, etc.
255
- // We need to convert: array index 0 -> shard 1, array index 1 -> shard 2, etc.
256
- if (shardIndex === currentJobIndex && currentJobIndex >= 0) {
257
- shardIndex = currentJobIndex + 1; // Convert 0-based array index to 1-based shard index
258
- }
259
-
260
- const totalShards = jobGroup.length;
261
- return {
262
- shardIndex,
263
- totalShards
264
- };
265
- } catch (error) {
266
- return null;
267
- }
268
- }
269
93
  async onEnd() {
270
94
  const { okToProceed, message } = this.preChecks();
271
95
  if (!okToProceed) {
@@ -275,108 +99,20 @@ class SlackReporter {
275
99
  // SHARDING SUPPORT - Stop slack messages for non-shard-1 shard(s)
276
100
  // Only shard 1 should post when aggregating results from multiple shards
277
101
 
278
- // Check if we're actually running in GitHub Actions (not just env vars set locally)
279
- const isActuallyInGitHubActions = process.env.GITHUB_ACTIONS === 'true' &&
280
- process.env.GITHUB_RUN_ID !== undefined &&
281
- process.env.GITHUB_RUNNER_NAME !== undefined;
282
-
283
- // Check Playwright's shard config (highest priority for local runs)
284
- let playwrightShardInfo = null;
285
- if (this.fullConfig) {
286
- if (this.fullConfig.shard) {
287
- // Playwright shard can be either { current, total } or undefined
288
- if (this.fullConfig.shard.current !== undefined && this.fullConfig.shard.total !== undefined) {
289
- playwrightShardInfo = {
290
- current: this.fullConfig.shard.current,
291
- total: this.fullConfig.shard.total
292
- };
293
- }
294
- }
295
- }
296
-
297
- // Also check if shard info is in process.argv (command line)
298
- // This is a fallback if config doesn't have it but --shard was passed
299
- if (!playwrightShardInfo && process.argv) {
300
- const shardArg = process.argv.find(arg => arg && arg.includes('--shard'));
301
- if (shardArg) {
302
- const shardMatch = shardArg.match(/--shard[=:]?(\d+)\/(\d+)/);
303
- if (shardMatch) {
304
- playwrightShardInfo = {
305
- current: parseInt(shardMatch[1], 10),
306
- total: parseInt(shardMatch[2], 10)
307
- };
308
- }
309
- }
310
- }
311
-
312
- // Step 1: Try GitHub Actions API detection (only if actually in GitHub Actions)
313
- let githubApiShardInfo = null;
314
- if (isActuallyInGitHubActions) {
315
- githubApiShardInfo = await this.detectGitHubActionsShardInfo();
316
- }
317
-
318
- // Step 2: Detect shard index (priority order: Playwright config > env vars > GitHub API)
319
- let currentShardIndex;
320
- if (playwrightShardInfo) {
321
- // Playwright uses 1-based indexing, keep it 1-based for shard 1 logic
322
- currentShardIndex = playwrightShardInfo.current.toString();
323
- } else if (process.env.SHARD_INDEX !== undefined) {
324
- currentShardIndex = process.env.SHARD_INDEX;
325
- } else if (process.env.MATRIX_SHARD !== undefined) {
326
- currentShardIndex = process.env.MATRIX_SHARD;
327
- } else if (process.env.MATRIX_INDEX !== undefined) {
328
- currentShardIndex = process.env.MATRIX_INDEX;
329
- } else if (githubApiShardInfo) {
330
- currentShardIndex = githubApiShardInfo.shardIndex.toString();
331
- }
332
-
333
- // Step 3: Get shard count from multiple sources (priority order)
334
- let totalShards;
335
- if (playwrightShardInfo) {
336
- totalShards = playwrightShardInfo.total;
337
- } else if (process.env.TOTAL_SHARDS !== undefined) {
338
- totalShards = parseInt(process.env.TOTAL_SHARDS, 10);
339
- } else if (process.env.MATRIX_COUNT !== undefined) {
340
- totalShards = parseInt(process.env.MATRIX_COUNT, 10);
341
- } else if (githubApiShardInfo && githubApiShardInfo.totalShards > 1) {
342
- totalShards = githubApiShardInfo.totalShards;
343
- } else {
344
- // Fallback to ResultsParser
345
- totalShards = this.resultsParser.totalShardCount;
346
- }
102
+ // Get shard info from environment variables
103
+ const currentShardIndex = process.env.SHARD_INDEX;
104
+ const totalShards = process.env.TOTAL_SHARDS ? parseInt(process.env.TOTAL_SHARDS, 10) : 1;
347
105
 
348
- // Get shard info from ResultsParser for fallback
349
- const parserShardIndex = this.resultsParser.shardIndex;
350
-
351
- // If we still don't have shard index, try to infer from parser or GitHub API
352
- if (currentShardIndex === undefined) {
353
- if (githubApiShardInfo && githubApiShardInfo.shardIndex !== undefined) {
354
- currentShardIndex = githubApiShardInfo.shardIndex.toString();
355
- } else if (parserShardIndex !== undefined) {
356
- currentShardIndex = parserShardIndex.toString();
357
- }
358
- }
359
-
360
- // CRITICAL: In CI (especially GitHub Actions), if we can't detect shard info, block posting
106
+ // CRITICAL: In CI, if we can't detect shard info, block posting
361
107
  // This prevents duplicate messages when running with multiple shards
362
- // BUT: Don't block if we're running locally (even if CI env vars are set)
363
- // Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4), but we use 0-based internally
364
- if (isActuallyInGitHubActions && currentShardIndex === undefined) {
365
- if (process.env.GITHUB_ACTIONS === 'true') {
366
- this.log(`❌ [Shard Detection] BLOCKING: GitHub Actions detected but shard index cannot be determined.`);
367
- this.log(`❌ Attempted: GitHub API detection ${githubApiShardInfo ? 'succeeded' : 'failed'}, env vars not set`);
368
- this.log(`❌ This prevents duplicate messages when running with multiple shards.`);
369
- } else {
370
- this.log(`❌ [Shard Detection] BLOCKING: CI environment detected but shard info not set.`);
371
- this.log(`❌ MATRIX_COUNT: undefined, MATRIX_SHARD: undefined`);
372
- this.log(`❌ This prevents duplicate messages when running with multiple shards.`);
373
- }
108
+ if (process.env.CI && currentShardIndex === undefined && totalShards > 1) {
109
+ this.log(`❌ [Shard Detection] BLOCKING: CI environment detected but SHARD_INDEX not set.`);
110
+ this.log(`❌ This prevents duplicate messages when running with multiple shards.`);
374
111
  this.log(`❌ Skipping Slack report to prevent duplicate messages from all shards.`);
375
- this.log(`💡 Fix: Add these env vars to your workflow:`);
112
+ this.log(`💡 Fix: Add SHARD_INDEX env var to your workflow:`);
376
113
  this.log(`💡 env:`);
377
- this.log(`💡 MATRIX_SHARD: $\{\{ strategy.job-index \}\} # GitHub Actions uses 1-based, convert to 0-based (only shard 1/internal index 1 posts)`);
378
- this.log(`💡 MATRIX_COUNT: $\{\{ strategy.job-total \}\}`);
379
- this.log(`💡 OR ensure SAFETYWINGTEST_GITHUB_TOKEN has workflow permissions for API detection`);
114
+ this.log(`💡 SHARD_INDEX: $\{\{ strategy.job-index \}\} # Only shard 1 should post`);
115
+ this.log(`💡 TOTAL_SHARDS: $\{\{ strategy.job-total \}\}`);
380
116
  return;
381
117
  }
382
118
 
@@ -387,37 +123,11 @@ class SlackReporter {
387
123
  // This ensures ResultsParser always has correct values, even if we block posting
388
124
  this.resultsParser.updateShardInfo(shardIndexNum, totalShards);
389
125
 
390
- // For local runs with CI env vars set but not actually in CI, allow posting if single shard
391
- // or if shard index is 1
392
- if (!isActuallyInGitHubActions && process.env.CI && totalShards > 1 && currentShardIndex === undefined) {
393
- this.log(`⚠️ [Shard Detection] Local run with CI env vars but shard info unclear - allowing post (may cause duplicates)`);
394
- }
395
-
396
- // CRITICAL: For GitHub Actions with multiple shards, only shard 1 should post
397
- // If we're in CI with multiple shards and don't know which shard we are, block all posts
398
- // This prevents duplicate messages when MATRIX_SHARD/MATRIX_INDEX is not set
399
- // Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4)
400
- // We use 0-based internally, so GitHub Actions shard 1 = internal index 1
401
- if (isActuallyInGitHubActions && totalShards > 1 && currentShardIndex === undefined) {
402
- this.log(`❌ [Shard Detection] BLOCKING: GitHub Actions detected with ${totalShards} shards but shard index not set (MATRIX_SHARD/MATRIX_INDEX missing).`);
403
- this.log(`❌ Skipping Slack report to prevent duplicate messages from all shards.`);
404
- this.log(`💡 Fix: Add these env vars to your workflow:`);
405
- this.log(`💡 env:`);
406
- this.log(`💡 MATRIX_SHARD: $\{\{ strategy.job-index \}\} # GitHub Actions uses 1-based, convert to 0-based (only shard 1/internal index 1 posts)`);
407
- this.log(`💡 MATRIX_COUNT: $\{\{ strategy.job-total \}\}`);
408
- this.log(`💡 OR ensure SAFETYWINGTEST_GITHUB_TOKEN has workflow permissions for API detection`);
409
- return;
410
- }
411
-
412
126
  // Only allow shard 1 to post when there are multiple shards
413
127
  // This ensures only one shard posts the aggregated report
414
- // Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4)
415
- // We use 0-based internally, so shard 1 in GitHub Actions = index 1 internally
416
128
  if (totalShards > 1 && shardIndexNum !== 1) {
417
- // Convert back to 1-based for display if from GitHub Actions
418
- const displayShard = isActuallyInGitHubActions ? shardIndexNum + 1 : shardIndexNum;
419
- this.log(`❌ [Shard Detection] BLOCKING: Non-shard-1 detected (shard ${displayShard} of ${totalShards}${isActuallyInGitHubActions ? ' [GitHub Actions 1-based]' : ''})`);
420
- this.log(`❌ Stopping reporter for shard ${displayShard} of ${totalShards}`);
129
+ this.log(`❌ [Shard Detection] BLOCKING: Non-shard-1 detected (shard ${shardIndexNum} of ${totalShards})`);
130
+ this.log(`❌ Stopping reporter for shard ${shardIndexNum} of ${totalShards}`);
421
131
  this.log(`ℹ️ Only shard 1 will post the aggregated report.`);
422
132
  return;
423
133
  }
@@ -426,9 +136,7 @@ class SlackReporter {
426
136
  if (totalShards === 1) {
427
137
  this.log(`✅ [Shard Detection] ALLOWING: Single shard detected. Posting Slack report.`);
428
138
  } else {
429
- // Convert back to 1-based for display if from GitHub Actions
430
- const displayShard = isActuallyInGitHubActions ? shardIndexNum + 1 : shardIndexNum;
431
- this.log(`✅ [Shard Detection] ALLOWING: Multiple shards detected (${totalShards}). Shard ${displayShard} (index ${shardIndexNum}${isActuallyInGitHubActions ? ', GitHub Actions 1-based' : ''}) will post aggregated report.`);
139
+ this.log(`✅ [Shard Detection] ALLOWING: Multiple shards detected (${totalShards}). Shard ${shardIndexNum} will post aggregated report.`);
432
140
  }
433
141
 
434
142
  const resultSummary = await this.resultsParser.getParsedResults();
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.21",
35
+ "version": "3.0.22",
36
36
  "main": "index.js",
37
37
  "types": "dist/index.d.ts",
38
38
  "author": "Burak B. <burak.boluk@hotmail.com>",