@m00nsolutions/playwright-reporter 1.0.8 → 1.0.10

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 M00n Solutions
3
+ Copyright (c) 2024 M00N Solutions
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -103,7 +103,6 @@ The following attributes are automatically populated when running in a supported
103
103
 
104
104
  | Attribute | Description | GitHub Actions | GitLab CI | Jenkins | Bitbucket | Azure DevOps | CircleCI | Travis CI |
105
105
  |---|---|---|---|---|---|---|---|---|
106
- | `ci_provider` | CI provider name | `GitHub Actions` | `GitLab CI` | `Jenkins` | `Bitbucket Pipelines` | `Azure DevOps` | `CircleCI` | `Travis CI` |
107
106
  | `branch` | Git branch | `GITHUB_REF_NAME` | `CI_COMMIT_REF_NAME` | `BRANCH_NAME` | `BITBUCKET_BRANCH` | `BUILD_SOURCEBRANCH` | `CIRCLE_BRANCH` | `TRAVIS_BRANCH` |
108
107
  | `commit` | Git commit SHA | `GITHUB_SHA` | `CI_COMMIT_SHA` | `GIT_COMMIT` | `BITBUCKET_COMMIT` | `BUILD_SOURCEVERSION` | `CIRCLE_SHA1` | `TRAVIS_COMMIT` |
109
108
  | `pipeline` | Pipeline/workflow name | `GITHUB_WORKFLOW` | `CI_PIPELINE_NAME` | `JOB_NAME` | - | `BUILD_DEFINITIONNAME` | `CIRCLE_WORKFLOW_JOB_NAME` | - |
@@ -143,7 +142,9 @@ attributes: {
143
142
  },
144
143
  ```
145
144
 
146
- The dashboard recognizes these attribute keys and displays them in the CI/CD banner: `branch`, `commit`, `pipeline`, `build_number`, `build_url`, `environment`, `trigger`.
145
+ The dashboard recognizes these attribute keys and displays them: `branch`, `commit`, `pipeline`, `build_number`, `build_url`, `environment`, `trigger`.
146
+
147
+ In addition, `branch` and `triggered_by` are surfaced on each **launch card** in the Launches list — so you can see at a glance who triggered each run and from which branch without opening the details panel. Both are auto-detected from CI env vars (see the table above) and can be overridden via `attributes`.
147
148
 
148
149
  ## Usage Examples
149
150
 
package/index.cjs CHANGED
@@ -1,20 +1,20 @@
1
- // CommonJS wrapper for M00n Playwright Reporter
1
+ // CommonJS wrapper for M00N Playwright Reporter
2
2
  // This allows the reporter to work with both ESM and CommonJS consumers
3
3
 
4
4
  // Dynamic import wrapper for ESM module
5
- let M00nReporter;
5
+ let M00NReporter;
6
6
 
7
7
  // Use dynamic import to load the ESM module
8
8
  const loadReporter = async () => {
9
- if (!M00nReporter) {
9
+ if (!M00NReporter) {
10
10
  const module = await import('./index.mjs');
11
- M00nReporter = module.default;
11
+ M00NReporter = module.default;
12
12
  }
13
- return M00nReporter;
13
+ return M00NReporter;
14
14
  };
15
15
 
16
16
  // Export a class that wraps the ESM reporter
17
- class M00nReporterWrapper {
17
+ class M00NReporterWrapper {
18
18
  constructor(options) {
19
19
  this.options = options;
20
20
  this.reporter = null;
@@ -65,5 +65,5 @@ class M00nReporterWrapper {
65
65
  }
66
66
  }
67
67
 
68
- module.exports = M00nReporterWrapper;
69
- module.exports.default = M00nReporterWrapper;
68
+ module.exports = M00NReporterWrapper;
69
+ module.exports.default = M00NReporterWrapper;
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // M00n Reporter v2 - Simplified Playwright reporter for M00N Report dashboard
1
+ // M00N Reporter v2 - Simplified Playwright reporter for M00N Report dashboard
2
2
  //
3
3
  // Key improvements over v1:
4
4
  // 1. Hybrid model - real-time step streaming + atomic final persistence
@@ -153,11 +153,11 @@ class FileLogger {
153
153
 
154
154
  // Write session header
155
155
  const header = `\n${'='.repeat(80)}\n` +
156
- `M00nReporter Performance Log - ${new Date().toISOString()}\n` +
156
+ `M00NReporter Performance Log - ${new Date().toISOString()}\n` +
157
157
  `${'='.repeat(80)}\n`;
158
158
  this.writeStream.write(header);
159
159
  } catch (err) {
160
- console.warn(`[M00nReporter] Failed to open log file: ${err.message}`);
160
+ console.warn(`[M00NReporter] Failed to open log file: ${err.message}`);
161
161
  this.enabled = false;
162
162
  }
163
163
  }
@@ -481,7 +481,6 @@ function detectCIAttributes() {
481
481
  const attrs = {};
482
482
 
483
483
  if (env.GITHUB_ACTIONS) {
484
- attrs.ci_provider = 'GitHub Actions';
485
484
  if (env.GITHUB_WORKFLOW) attrs.pipeline = env.GITHUB_WORKFLOW;
486
485
  if (env.GITHUB_RUN_NUMBER) attrs.build_number = env.GITHUB_RUN_NUMBER;
487
486
  if (env.GITHUB_SHA) attrs.commit = env.GITHUB_SHA;
@@ -493,7 +492,6 @@ function detectCIAttributes() {
493
492
  attrs.build_url = `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}`;
494
493
  }
495
494
  } else if (env.GITLAB_CI) {
496
- attrs.ci_provider = 'GitLab CI';
497
495
  if (env.CI_PIPELINE_NAME) attrs.pipeline = env.CI_PIPELINE_NAME;
498
496
  if (env.CI_PIPELINE_ID) attrs.build_number = env.CI_PIPELINE_ID;
499
497
  if (env.CI_PIPELINE_URL) attrs.build_url = env.CI_PIPELINE_URL;
@@ -503,7 +501,6 @@ function detectCIAttributes() {
503
501
  if (env.CI_JOB_URL) attrs.ci_job_url = env.CI_JOB_URL;
504
502
  if (env.CI_GITLAB_USER_LOGIN) attrs.triggered_by = env.CI_GITLAB_USER_LOGIN;
505
503
  } else if (env.JENKINS_URL) {
506
- attrs.ci_provider = 'Jenkins';
507
504
  if (env.JOB_NAME) attrs.pipeline = env.JOB_NAME;
508
505
  if (env.BUILD_NUMBER) attrs.build_number = env.BUILD_NUMBER;
509
506
  if (env.BUILD_URL) attrs.build_url = env.BUILD_URL;
@@ -511,7 +508,6 @@ function detectCIAttributes() {
511
508
  if (env.BRANCH_NAME) attrs.branch = env.BRANCH_NAME;
512
509
  else if (env.GIT_BRANCH) attrs.branch = env.GIT_BRANCH;
513
510
  } else if (env.BITBUCKET_PIPELINE_UUID) {
514
- attrs.ci_provider = 'Bitbucket Pipelines';
515
511
  if (env.BITBUCKET_BUILD_NUMBER) attrs.build_number = env.BITBUCKET_BUILD_NUMBER;
516
512
  if (env.BITBUCKET_COMMIT) attrs.commit = env.BITBUCKET_COMMIT;
517
513
  if (env.BITBUCKET_BRANCH) attrs.branch = env.BITBUCKET_BRANCH;
@@ -519,7 +515,6 @@ function detectCIAttributes() {
519
515
  attrs.build_url = `https://bitbucket.org/${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}/pipelines/results/${env.BITBUCKET_BUILD_NUMBER}`;
520
516
  }
521
517
  } else if (env.TF_BUILD) {
522
- attrs.ci_provider = 'Azure DevOps';
523
518
  if (env.BUILD_DEFINITIONNAME) attrs.pipeline = env.BUILD_DEFINITIONNAME;
524
519
  if (env.BUILD_BUILDNUMBER) attrs.build_number = env.BUILD_BUILDNUMBER;
525
520
  if (env.BUILD_SOURCEVERSION) attrs.commit = env.BUILD_SOURCEVERSION;
@@ -529,7 +524,6 @@ function detectCIAttributes() {
529
524
  attrs.build_url = `${env.SYSTEM_TEAMFOUNDATIONSERVERURI}${env.SYSTEM_TEAMPROJECT}/_build/results?buildId=${env.BUILD_BUILDID}`;
530
525
  }
531
526
  } else if (env.CIRCLECI) {
532
- attrs.ci_provider = 'CircleCI';
533
527
  if (env.CIRCLE_WORKFLOW_JOB_NAME) attrs.pipeline = env.CIRCLE_WORKFLOW_JOB_NAME;
534
528
  if (env.CIRCLE_BUILD_NUM) attrs.build_number = env.CIRCLE_BUILD_NUM;
535
529
  if (env.CIRCLE_BUILD_URL) attrs.build_url = env.CIRCLE_BUILD_URL;
@@ -537,7 +531,6 @@ function detectCIAttributes() {
537
531
  if (env.CIRCLE_BRANCH) attrs.branch = env.CIRCLE_BRANCH;
538
532
  if (env.CIRCLE_USERNAME) attrs.triggered_by = env.CIRCLE_USERNAME;
539
533
  } else if (env.TRAVIS) {
540
- attrs.ci_provider = 'Travis CI';
541
534
  if (env.TRAVIS_BUILD_NUMBER) attrs.build_number = env.TRAVIS_BUILD_NUMBER;
542
535
  if (env.TRAVIS_BUILD_WEB_URL) attrs.build_url = env.TRAVIS_BUILD_WEB_URL;
543
536
  if (env.TRAVIS_COMMIT) attrs.commit = env.TRAVIS_COMMIT;
@@ -753,7 +746,7 @@ class HttpClient {
753
746
 
754
747
  try {
755
748
  // Build multipart boundary
756
- const boundary = `----M00nReporter${crypto.randomUUID().replace(/-/g, '')}`;
749
+ const boundary = `----M00NReporter${crypto.randomUUID().replace(/-/g, '')}`;
757
750
  const parts = [];
758
751
 
759
752
  // Add text fields
@@ -900,7 +893,7 @@ class HttpClient {
900
893
  fileSize = stats.size;
901
894
 
902
895
  // Build multipart body with streaming
903
- const boundary = `----M00nReporter${crypto.randomUUID().replace(/-/g, '')}`;
896
+ const boundary = `----M00NReporter${crypto.randomUUID().replace(/-/g, '')}`;
904
897
 
905
898
  // Build header parts (before file content)
906
899
  const headerParts = [];
@@ -1293,11 +1286,13 @@ class TestCollector {
1293
1286
  if (stats.size > MAX_ATTACHMENT_SIZE) {
1294
1287
  const sizeMB = (stats.size / 1024 / 1024).toFixed(1);
1295
1288
  const limitMB = (MAX_ATTACHMENT_SIZE / 1024 / 1024).toFixed(0);
1296
- console.warn(`[M00nReporter] Attachment skipped: "${name}" (${sizeMB}MB) exceeds ${limitMB}MB limit. File: ${attachment.path}`);
1289
+ console.warn(`[M00NReporter] Attachment skipped: "${name}" (${sizeMB}MB) exceeds ${limitMB}MB limit. File: ${attachment.path}`);
1297
1290
  return null;
1298
1291
  }
1299
1292
 
1300
- if (name === 'trace') name = path.basename(attachment.path);
1293
+ // Use actual filename from path instead of generic Playwright names (e.g., "screenshot" -> "screenshot.png")
1294
+ // Traces already had this behavior; now all file-based attachments get real filenames
1295
+ name = path.basename(attachment.path);
1301
1296
 
1302
1297
  // Large file: store path for streaming upload (no buffering!)
1303
1298
  if (stats.size > LARGE_FILE_THRESHOLD && binaryMode) {
@@ -1346,9 +1341,9 @@ class TestCollector {
1346
1341
  // 2. Race condition where video file is deleted before reporter reads it
1347
1342
  // 3. Disk space issues during high-concurrency runs
1348
1343
  if (fileErr.code === 'ENOENT') {
1349
- console.warn(`[M00nReporter] Video/attachment file not found: ${attachment.path} - file may have been cleaned up by Playwright`);
1344
+ console.warn(`[M00NReporter] Video/attachment file not found: ${attachment.path} - file may have been cleaned up by Playwright`);
1350
1345
  } else {
1351
- console.warn(`[M00nReporter] Failed to read attachment file ${attachment.path}: ${fileErr.message}`);
1346
+ console.warn(`[M00NReporter] Failed to read attachment file ${attachment.path}: ${fileErr.message}`);
1352
1347
  }
1353
1348
  return null;
1354
1349
  }
@@ -1402,7 +1397,7 @@ class TestCollector {
1402
1397
  // REPORTER
1403
1398
  // ============================================================================
1404
1399
 
1405
- export default class M00nReporter {
1400
+ export default class M00NReporter {
1406
1401
  constructor(options = {}) {
1407
1402
  this.opts = options;
1408
1403
  this.debug = options.debug || false;
@@ -1534,7 +1529,7 @@ export default class M00nReporter {
1534
1529
  log(level, ...args) {
1535
1530
  if (level === 'debug' && !this.debug) return;
1536
1531
  if (level === 'perf' && !this.verbose) return;
1537
- const prefix = '[M00nReporter]';
1532
+ const prefix = '[M00NReporter]';
1538
1533
  const timestamp = this.verbose ? `[${((Date.now() - this.perfTracker.startTime) / 1000).toFixed(2)}s]` : '';
1539
1534
  if (level === 'error') console.error(prefix, timestamp, ...args);
1540
1535
  else if (level === 'warn') console.warn(prefix, timestamp, ...args);
@@ -1579,12 +1574,7 @@ export default class M00nReporter {
1579
1574
  ? this.opts.attributes
1580
1575
  : {};
1581
1576
  const attributes = { ...ciAttrs, ...userAttrs };
1582
-
1583
- // Add workers count from Playwright config (useful for timeline visualization)
1584
- if (config.workers != null) {
1585
- attributes.workers = config.workers;
1586
- }
1587
-
1577
+
1588
1578
  // Project is determined by the API key - no need to send projectId
1589
1579
  const runStartPromise = this.http.post('/api/ingest/v2/run/start', {
1590
1580
  launch,
@@ -2413,7 +2403,7 @@ export default class M00nReporter {
2413
2403
 
2414
2404
  printSummary() {
2415
2405
  console.log('\n' + '═'.repeat(60));
2416
- console.log('[M00nReporter] Run Summary');
2406
+ console.log('[M00NReporter] Run Summary');
2417
2407
  console.log('─'.repeat(60));
2418
2408
  console.log(` Run ID: ${this.runId || 'N/A'}`);
2419
2409
  console.log(` Tests: ${this.stats.testsReported}/${this.stats.testsStarted} reported`);
@@ -2439,7 +2429,7 @@ export default class M00nReporter {
2439
2429
  const perf = this.perfTracker.generateReport();
2440
2430
  if (perf) {
2441
2431
  console.log('─'.repeat(60));
2442
- console.log('[M00nReporter] Performance Report');
2432
+ console.log('[M00NReporter] Performance Report');
2443
2433
  console.log('─'.repeat(60));
2444
2434
  console.log(` Total Duration: ${perf.duration}`);
2445
2435
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m00nsolutions/playwright-reporter",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Playwright test reporter for M00N Report dashboard - real-time test result streaming with step tracking, attachments, and retry support",
5
5
  "main": "index.mjs",
6
6
  "type": "module",
@@ -35,11 +35,11 @@
35
35
  "e2e",
36
36
  "end-to-end"
37
37
  ],
38
- "author": "M00n Solutions",
38
+ "author": "M00N Solutions",
39
39
  "license": "MIT",
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/m00nsolutions/m00nreport.git",
42
+ "url": "git+https://github.com/m00nsolutions/m00nreport.git",
43
43
  "directory": "packages/m00n-playwright-reporter"
44
44
  },
45
45
  "homepage": "https://m00nreport.com",