reporting-labs 0.6.0 → 0.6.1
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/README.md +156 -20
- package/bin/build-template.js +101 -0
- package/dist/template.html +1659 -0
- package/dist/template.js +217 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -267,7 +267,7 @@ Legend: ✅ built in · 🟡 possible with manual setup or extra config · ❌ n
|
|
|
267
267
|
| Secrets masked | ❌ | 🟡 parameter masking | ✅ automatic |
|
|
268
268
|
| CSV / JSON export of failures, Slack summary | ❌ | ❌ | ✅ |
|
|
269
269
|
| Timeline by worker | ❌ | ✅ | ✅ |
|
|
270
|
-
| Combine shards / several runs | ✅ blob + `merge-reports` | ✅ Launches |
|
|
270
|
+
| Combine shards / several runs | ✅ blob + `merge-reports` | ✅ Launches | ✅ `reporting-labs merge` |
|
|
271
271
|
| Frameworks beyond Playwright | ❌ | ✅ many languages | ❌ on the roadmap |
|
|
272
272
|
| Free and open source | ✅ | ✅ (Allure TestOps is a separate paid product) | ✅ MIT |
|
|
273
273
|
|
|
@@ -352,39 +352,100 @@ Ready-to-copy samples: [github-actions.yml](https://github.com/naveenautomationl
|
|
|
352
352
|
|
|
353
353
|
### Split your run across shards, then merge into one report
|
|
354
354
|
|
|
355
|
-
Big test suite?
|
|
355
|
+
Big test suite? Split it into shards so they run in parallel, then join every shard's report into one HTML at the end. Works on your laptop and on any CI.
|
|
356
356
|
|
|
357
|
-
**
|
|
357
|
+
**What happens under the hood.** Each shard runs the reporter and writes its own `reporting-labs/` folder with `index.html` plus a small `report.json` next to it. The `merge` command reads every shard's `report.json`, combines them into one dataset, copies attachments into per-shard subfolders so nothing overwrites, and renders one HTML with all tests, one Trend chart, one Failure Clusters view, and a Shards row in the Environment card.
|
|
358
358
|
|
|
359
|
-
|
|
360
|
-
|
|
359
|
+
Nothing extra to install and no config change needed. The reporter writes `report.json` on every run out of the box.
|
|
360
|
+
|
|
361
|
+
#### Try it on your laptop first
|
|
362
|
+
|
|
363
|
+
Three shards, run one after another (on a single machine you cannot really run them in parallel, but this proves the merge works end to end):
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Delete leftovers from any previous run
|
|
367
|
+
rm -rf all-shards merged
|
|
368
|
+
|
|
369
|
+
# Run each shard and move its folder aside so the next shard does not overwrite it
|
|
370
|
+
mkdir -p all-shards
|
|
371
|
+
npx playwright test --shard=1/3 && mv reporting-labs all-shards/s1
|
|
372
|
+
npx playwright test --shard=2/3 && mv reporting-labs all-shards/s2
|
|
373
|
+
npx playwright test --shard=3/3 && mv reporting-labs all-shards/s3
|
|
374
|
+
|
|
375
|
+
# One command combines them
|
|
376
|
+
npx reporting-labs merge all-shards -o merged
|
|
377
|
+
|
|
378
|
+
# Open it
|
|
379
|
+
open merged/index.html # macOS
|
|
380
|
+
# start merged/index.html # Windows
|
|
381
|
+
# xdg-open merged/index.html # Linux
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Look for this line in each `npx playwright test` output:
|
|
385
|
+
|
|
386
|
+
```
|
|
387
|
+
reporting-labs: report written to reporting-labs/index.html
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
That line proves the reporter ran and the folder exists to move. If you do not see it, your `playwright.config.ts` is not wiring `reporting-labs` as a reporter yet — see the [Quick start](#quick-start-2-minutes).
|
|
391
|
+
|
|
392
|
+
**Custom output folder?** If your config has `outputFolder: 'my-report'`, use that name in the move step:
|
|
361
393
|
|
|
362
394
|
```bash
|
|
363
|
-
|
|
395
|
+
mv my-report all-shards/s1
|
|
364
396
|
```
|
|
365
397
|
|
|
366
|
-
|
|
398
|
+
**One-liner for a real parallel run on your laptop.** Runs three shards at once, then merges when all three finish:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
rm -rf all-shards merged && mkdir -p all-shards
|
|
402
|
+
(npx playwright test --shard=1/3 && mv reporting-labs all-shards/s1) &
|
|
403
|
+
(npx playwright test --shard=2/3 && mv reporting-labs all-shards/s2) &
|
|
404
|
+
(npx playwright test --shard=3/3 && mv reporting-labs all-shards/s3) &
|
|
405
|
+
wait
|
|
406
|
+
npx reporting-labs merge all-shards -o merged
|
|
407
|
+
open merged/index.html
|
|
408
|
+
```
|
|
367
409
|
|
|
368
|
-
|
|
369
|
-
- Combined pass / fail / flaky numbers on top
|
|
370
|
-
- One Trend chart, one Environment card, one Failure Clusters view
|
|
371
|
-
- Screenshots and videos kept in `merged/assets/shard-1-of-4/`, `merged/assets/shard-2-of-4/`, so nothing overwrites
|
|
410
|
+
#### GitHub Actions
|
|
372
411
|
|
|
373
|
-
|
|
412
|
+
Each shard runs on its own runner in parallel, then a final `merge` job downloads every shard's report and combines them. Copy-paste as `.github/workflows/tests.yml` in your repo:
|
|
374
413
|
|
|
375
414
|
```yaml
|
|
415
|
+
name: Playwright tests
|
|
416
|
+
|
|
417
|
+
on:
|
|
418
|
+
push:
|
|
419
|
+
branches: [main]
|
|
420
|
+
pull_request:
|
|
421
|
+
|
|
376
422
|
jobs:
|
|
377
423
|
test:
|
|
378
|
-
|
|
379
|
-
matrix: { shard: [1, 2, 3, 4] }
|
|
424
|
+
name: shard ${{ matrix.shard }}/4
|
|
380
425
|
runs-on: ubuntu-latest
|
|
426
|
+
strategy:
|
|
427
|
+
fail-fast: false
|
|
428
|
+
matrix:
|
|
429
|
+
shard: [1, 2, 3, 4]
|
|
381
430
|
steps:
|
|
382
431
|
- uses: actions/checkout@v4
|
|
383
432
|
- uses: actions/setup-node@v4
|
|
384
433
|
with: { node-version: 20, cache: npm }
|
|
385
434
|
- run: npm ci
|
|
386
435
|
- run: npx playwright install --with-deps
|
|
436
|
+
|
|
437
|
+
# Keep the history file across runs so the Trend and new-vs-known
|
|
438
|
+
# failures build up over time. Each shard reads the same file.
|
|
439
|
+
- uses: actions/cache@v4
|
|
440
|
+
with:
|
|
441
|
+
path: reporting-labs.history.json
|
|
442
|
+
key: reporting-labs-history-${{ github.ref_name }}-${{ github.run_id }}
|
|
443
|
+
restore-keys: |
|
|
444
|
+
reporting-labs-history-${{ github.ref_name }}-
|
|
445
|
+
|
|
387
446
|
- run: npx playwright test --shard=${{ matrix.shard }}/4
|
|
447
|
+
|
|
448
|
+
# Save this shard's report so the merge job can pick it up.
|
|
388
449
|
- uses: actions/upload-artifact@v4
|
|
389
450
|
if: always()
|
|
390
451
|
with:
|
|
@@ -393,6 +454,7 @@ jobs:
|
|
|
393
454
|
retention-days: 30
|
|
394
455
|
|
|
395
456
|
merge:
|
|
457
|
+
name: merge shards into one report
|
|
396
458
|
if: always()
|
|
397
459
|
needs: test
|
|
398
460
|
runs-on: ubuntu-latest
|
|
@@ -401,17 +463,91 @@ jobs:
|
|
|
401
463
|
- uses: actions/setup-node@v4
|
|
402
464
|
with: { node-version: 20, cache: npm }
|
|
403
465
|
- run: npm ci
|
|
466
|
+
|
|
467
|
+
# Downloads every 'report-shard-N' artifact under ./all-shards/report-shard-N/
|
|
404
468
|
- uses: actions/download-artifact@v4
|
|
405
|
-
with:
|
|
406
|
-
|
|
469
|
+
with:
|
|
470
|
+
path: all-shards
|
|
471
|
+
pattern: report-shard-*
|
|
472
|
+
|
|
473
|
+
- run: npx reporting-labs merge all-shards -o merged
|
|
474
|
+
|
|
475
|
+
# This is the artifact your team downloads and opens.
|
|
407
476
|
- uses: actions/upload-artifact@v4
|
|
408
|
-
with:
|
|
477
|
+
with:
|
|
478
|
+
name: merged-report
|
|
479
|
+
path: merged/
|
|
480
|
+
retention-days: 30
|
|
409
481
|
```
|
|
410
482
|
|
|
411
|
-
**
|
|
483
|
+
Download the **merged-report** artifact from the run's summary page and open `index.html` locally.
|
|
484
|
+
|
|
485
|
+
#### Jenkins
|
|
486
|
+
|
|
487
|
+
Four shards run in parallel via a matrix pipeline, then a final stage merges. Copy-paste as `Jenkinsfile`:
|
|
488
|
+
|
|
489
|
+
```groovy
|
|
490
|
+
pipeline {
|
|
491
|
+
agent any
|
|
492
|
+
options { timestamps() }
|
|
493
|
+
|
|
494
|
+
stages {
|
|
495
|
+
stage('Install') {
|
|
496
|
+
steps {
|
|
497
|
+
sh 'npm ci'
|
|
498
|
+
sh 'npx playwright install --with-deps'
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
stage('Run shards in parallel') {
|
|
503
|
+
matrix {
|
|
504
|
+
axes {
|
|
505
|
+
axis { name 'SHARD'; values '1', '2', '3', '4' }
|
|
506
|
+
}
|
|
507
|
+
stages {
|
|
508
|
+
stage('Test') {
|
|
509
|
+
steps {
|
|
510
|
+
sh "npx playwright test --shard=${SHARD}/4"
|
|
511
|
+
// Save each shard's report so the merge stage can unpack it later.
|
|
512
|
+
stash name: "report-shard-${SHARD}", includes: 'reporting-labs/**'
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
stage('Merge into one report') {
|
|
520
|
+
steps {
|
|
521
|
+
sh 'rm -rf all-shards merged && mkdir -p all-shards'
|
|
522
|
+
script {
|
|
523
|
+
['1', '2', '3', '4'].each { s ->
|
|
524
|
+
dir("all-shards/shard-${s}") { unstash "report-shard-${s}" }
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// Unstash lands the folder as all-shards/shard-N/reporting-labs/... — flatten it.
|
|
528
|
+
sh '''
|
|
529
|
+
for d in all-shards/shard-*; do
|
|
530
|
+
mv "$d/reporting-labs/"* "$d/"
|
|
531
|
+
rmdir "$d/reporting-labs"
|
|
532
|
+
done
|
|
533
|
+
'''
|
|
534
|
+
sh 'npx reporting-labs merge all-shards -o merged'
|
|
535
|
+
archiveArtifacts artifacts: 'merged/**', allowEmptyArchive: false
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Jenkins blocks inline JavaScript inside the HTML Publisher by default (Playwright's own HTML report has the same limitation), so the fastest way to view the merged report is to download the `merged/` folder from the build's artifacts and open `index.html` locally. If a Jenkins admin can relax the policy in the script console with `System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")`, you can also add a `publishHTML` step to open the report right from the build page.
|
|
543
|
+
|
|
544
|
+
#### Troubleshooting
|
|
412
545
|
|
|
413
|
-
- The reporter
|
|
414
|
-
-
|
|
546
|
+
- **`mv: reporting-labs: No such file or directory`.** The reporter did not run. Check `playwright.config.ts`: `reporter: [['list'], ['reporting-labs', reportingLabs]]`. Without that line, `npx playwright test` does not create the `reporting-labs/` folder.
|
|
547
|
+
- **A shard reports "0 tests".** Playwright shards by spec file by default, so if you have fewer spec files than shards, some shards will be empty. Reduce the shard count, split large specs, or upgrade to Playwright 1.51+ and set `shardingMode: 'round-robin'` for per-test sharding. The merge still works either way.
|
|
548
|
+
- **The Trend chart looks off after merging.** All shards read the same history file at startup, so the current run is recorded once by whichever shard writes last. On CI, cache the history file (see the GitHub Actions example above) so future runs pick it up.
|
|
549
|
+
- **`merge` says "no report.json under ...".** The folder you pointed at does not contain a shard's report. `merge` accepts either individual shard folders (each with `report.json`) or one parent folder that has many shards as subfolders. Check that `report.json` actually exists inside — the reporter writes it on every run unless you set `emitJson: false`.
|
|
550
|
+
- **Attachments broken in the merged report.** Screenshots are usually embedded inline as base64, so they always work. Videos and traces live in `merged/assets/shard-N-of-M/` — the merge rewrites paths so they resolve correctly. If a video does not play, open the merged folder locally (not from a Jenkins URL that strips inline JS).
|
|
415
551
|
|
|
416
552
|
### Slack, email, Teams: use your CI's own integration
|
|
417
553
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Emit dist/template.html — the same HTML shell renderHtml produces, but with
|
|
3
|
+
// well-known placeholders for the fields any language port (Java today, more
|
|
4
|
+
// later) needs to inject at render time:
|
|
5
|
+
//
|
|
6
|
+
// __RL_DATA__ — the report data JSON (the only required one)
|
|
7
|
+
// __RL_ACCENT_CSS__ — a :root{--accent:...} block, or empty
|
|
8
|
+
// __RL_CUSTOM_CSS__ — extra CSS the caller wants appended, or empty
|
|
9
|
+
//
|
|
10
|
+
// The placeholders are seeded with distinctive sentinels and then rewritten,
|
|
11
|
+
// so the surrounding CSS/HTML stays exactly what renderHtml produces.
|
|
12
|
+
//
|
|
13
|
+
// Runs AFTER `tsc` (dist/template.js has to exist).
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const { renderHtml } = require('../dist/template');
|
|
20
|
+
|
|
21
|
+
const ACCENT_SENTINEL = '__RL_ACCENT_SENTINEL_1a56db_2026__';
|
|
22
|
+
const CUSTOM_SENTINEL = '/*__RL_CUSTOM_CSS_SENTINEL_2026__*/';
|
|
23
|
+
|
|
24
|
+
const seed = {
|
|
25
|
+
title: '',
|
|
26
|
+
generatedAt: 0,
|
|
27
|
+
startTime: 0,
|
|
28
|
+
duration: 0,
|
|
29
|
+
metadata: {},
|
|
30
|
+
projects: [],
|
|
31
|
+
workers: 1,
|
|
32
|
+
stats: { total: 0, passed: 0, failed: 0, flaky: 0, skipped: 0 },
|
|
33
|
+
tests: [],
|
|
34
|
+
history: [],
|
|
35
|
+
bdd: false,
|
|
36
|
+
rootDir: '',
|
|
37
|
+
env: [],
|
|
38
|
+
runStatus: 'passed',
|
|
39
|
+
globalErrors: [],
|
|
40
|
+
globalOutput: [],
|
|
41
|
+
options: {
|
|
42
|
+
theme: 'auto',
|
|
43
|
+
palette: 'lab',
|
|
44
|
+
embedFonts: true,
|
|
45
|
+
sections: [],
|
|
46
|
+
widgets: {
|
|
47
|
+
overviewCards: true,
|
|
48
|
+
breakdown: true,
|
|
49
|
+
needsAttention: true,
|
|
50
|
+
failureClusters: true,
|
|
51
|
+
trend: true,
|
|
52
|
+
slowest: true,
|
|
53
|
+
env: true,
|
|
54
|
+
},
|
|
55
|
+
dimensions: ['priority', 'severity', 'owner', 'feature'],
|
|
56
|
+
dimensionOrder: {},
|
|
57
|
+
links: {},
|
|
58
|
+
// Seed accent + customCss with sentinels so we know exactly where they
|
|
59
|
+
// ended up in the rendered HTML.
|
|
60
|
+
accent: ACCENT_SENTINEL,
|
|
61
|
+
customCss: CUSTOM_SENTINEL,
|
|
62
|
+
editorLinks: true,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
let html = renderHtml(seed);
|
|
67
|
+
|
|
68
|
+
// Data payload placeholder.
|
|
69
|
+
const dataRe = /<script id="rl-data" type="application\/json">[^<]*<\/script>/;
|
|
70
|
+
if (!dataRe.test(html)) {
|
|
71
|
+
console.error('build-template: could not find rl-data script tag');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
html = html.replace(
|
|
75
|
+
dataRe,
|
|
76
|
+
'<script id="rl-data" type="application/json">__RL_DATA__</script>'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Accent + customCss placeholders. renderHtml renders:
|
|
80
|
+
// `:root{--accent:${accent}!important}` when accent is truthy,
|
|
81
|
+
// then appends customCss verbatim.
|
|
82
|
+
// Replace those sentinel-anchored spans with named placeholders that hold
|
|
83
|
+
// nothing by default; the port fills them in at render time.
|
|
84
|
+
const accentBlock = `:root{--accent:${ACCENT_SENTINEL}!important}`;
|
|
85
|
+
if (!html.includes(accentBlock)) {
|
|
86
|
+
console.error('build-template: accent sentinel not found in rendered HTML');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
html = html.replace(accentBlock, '__RL_ACCENT_CSS__');
|
|
90
|
+
|
|
91
|
+
if (!html.includes(CUSTOM_SENTINEL)) {
|
|
92
|
+
console.error('build-template: customCss sentinel not found in rendered HTML');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
html = html.replace(CUSTOM_SENTINEL, '__RL_CUSTOM_CSS__');
|
|
96
|
+
|
|
97
|
+
const out = path.join(__dirname, '..', 'dist', 'template.html');
|
|
98
|
+
fs.writeFileSync(out, html);
|
|
99
|
+
|
|
100
|
+
const sizeKb = (Buffer.byteLength(html) / 1024).toFixed(1);
|
|
101
|
+
console.log(`build-template: wrote ${out} (${sizeKb} KB)`);
|