@reportforge/playwright-pdf 0.24.0 → 0.26.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.
Files changed (31) hide show
  1. package/README.md +9 -6
  2. package/ci-templates/azure-devops/azure-pipelines.yml +58 -58
  3. package/ci-templates/github-actions/basic-workflow.yml +44 -44
  4. package/ci-templates/gitlab-ci/.gitlab-ci.yml +42 -42
  5. package/ci-templates/jenkins/Jenkinsfile +54 -54
  6. package/dist/cli/index.js +24 -1
  7. package/dist/index.d.mts +9 -3
  8. package/dist/index.d.ts +9 -3
  9. package/dist/index.js +407 -44
  10. package/dist/index.mjs +407 -44
  11. package/dist/templates/layouts/detailed.hbs +43 -41
  12. package/dist/templates/layouts/executive.hbs +43 -41
  13. package/dist/templates/layouts/minimal.hbs +43 -41
  14. package/dist/templates/partials/analysis-oneliner.hbs +3 -3
  15. package/dist/templates/partials/chart-summary-grid.hbs +40 -40
  16. package/dist/templates/partials/chart-trend-card.hbs +16 -16
  17. package/dist/templates/partials/charts.hbs +433 -433
  18. package/dist/templates/partials/ci-environment.hbs +56 -56
  19. package/dist/templates/partials/cover-page.hbs +48 -48
  20. package/dist/templates/partials/defect-log.hbs +79 -79
  21. package/dist/templates/partials/executive-hero-summary.hbs +66 -66
  22. package/dist/templates/partials/executive-summary.hbs +78 -78
  23. package/dist/templates/partials/failure-card.hbs +35 -35
  24. package/dist/templates/partials/head.hbs +17 -17
  25. package/dist/templates/partials/release-gate.hbs +84 -84
  26. package/dist/templates/partials/requirements-matrix.hbs +51 -51
  27. package/dist/templates/partials/run-diff.hbs +41 -0
  28. package/dist/templates/partials/suite-breakdown.hbs +89 -89
  29. package/dist/templates/partials/watermark.hbs +42 -42
  30. package/dist/templates/styles/base.css +19 -1
  31. package/package.json +1 -2
@@ -1,89 +1,89 @@
1
- <div class="section section--suite-breakdown">
2
- <h2>Suite Breakdown</h2>
3
- {{#if (and overflowFailureCount sections.failureDeepDive)}}
4
- <div class="overflow-banner">
5
- Inline failure detail covers the first {{failures.length}} failures.
6
- {{overflowFailureCount}} more {{#if (gt overflowFailureCount 1)}}are{{else}}is{{/if}}
7
- available in <code>{{overflowSidecarName}}</code> alongside this report.
8
- </div>
9
- {{/if}}
10
- {{#each projects}}
11
- <h3 style="color:var(--primary,#CC785C);margin-bottom:8px;">{{name}}</h3>
12
- {{#each suites}}
13
- {{> suite-node this depth=0}}
14
- {{/each}}
15
- {{/each}}
16
- </div>
17
-
18
- {{#*inline "suite-node"}}
19
- <div class="suite-group">
20
- <div class="suite-group__header">
21
- <span class="suite-title">{{title}}</span>
22
- <span class="suite-stats">
23
- {{#if stats.passed}}<span class="badge badge--passed">{{stats.passed}}</span>{{/if}}
24
- {{#if stats.failed}}<span class="badge badge--failed">{{stats.failed}}</span>{{/if}}
25
- {{#if stats.timedOut}}<span class="badge badge--timedout">{{stats.timedOut}}</span>{{/if}}
26
- {{#if stats.skipped}}<span class="badge badge--skipped">{{stats.skipped}}</span>{{/if}}
27
- {{#if stats.flaky}}<span class="badge badge--flaky">{{stats.flaky}}</span>{{/if}}
28
- </span>
29
- </div>
30
- {{#if tests.length}}
31
- <table>
32
- <thead>
33
- <tr>
34
- <th>Test</th>
35
- <th style="width:112px;">Status</th>
36
- <th style="width:72px;">Duration</th>
37
- {{#if @root.options.showRetries}}<th style="width:52px;">Retries</th>{{/if}}
38
- </tr>
39
- </thead>
40
- <tbody>
41
- {{#each tests}}
42
- <tr class="no-break{{#if failure}} test-row--has-detail{{/if}}">
43
- <td>
44
- <div style="font-weight:500;">{{title}}</div>
45
- {{#if location}}<div class="test-path">{{location}}</div>{{/if}}
46
- {{#if tags.length}}
47
- <div style="margin-top:3px;">
48
- {{#each tags}}<code style="font-size:8.5px;background:var(--surface-3);color:var(--text-3);padding:1px 5px;border-radius:3px;margin-right:3px;border:1px solid var(--border);">{{this}}</code>{{/each}}
49
- </div>
50
- {{/if}}
51
- </td>
52
- <td style="white-space:nowrap;">
53
- {{statusBadge status}}{{#if slowRank}}<span class="badge badge--slow" title="Among the slowest tests">SLOW</span>{{/if}}
54
- </td>
55
- <td style="color:var(--text-2);font-family:'JetBrains Mono',monospace;font-size:9.5px;">{{formatDuration duration}}</td>
56
- {{#if @root.options.showRetries}}<td style="color:var(--text-3);text-align:center;">{{retryCount}}</td>{{/if}}
57
- </tr>
58
- {{#if failure}}
59
- <tr class="failure-row">
60
- <td colspan="{{#if @root.options.showRetries}}4{{else}}3{{/if}}">
61
- <div class="failure-detail failure-detail--{{failure.severity}}">
62
- <div class="failure-detail__head">
63
- <span class="failure-detail__dot"></span>
64
- <span class="failure-detail__sev">{{failure.severity}} severity</span>
65
- </div>
66
- {{> failure-card failure=failure showFull=@root.options.showFullFailures showStack=@root.options.showStackTraces}}
67
- {{#if chip}}
68
- <div class="root-cause-chip root-cause-chip--{{chip.category}}">
69
- <span class="root-cause-chip__tag">Root cause</span>
70
- <span class="root-cause-chip__label">{{categoryLabel chip.category}}</span>
71
- <span class="root-cause-chip__msg">{{chip.message}}</span>
72
- <span class="root-cause-chip__strength">{{strengthLabel chip.strength}} match</span>
73
- </div>
74
- {{/if}}
75
- </div>
76
- </td>
77
- </tr>
78
- {{/if}}
79
- {{/each}}
80
- </tbody>
81
- </table>
82
- {{/if}}
83
- {{#each suites}}
84
- <div style="padding-left:14px;border-left:1px solid var(--border);margin:4px 8px;">
85
- {{> suite-node this}}
86
- </div>
87
- {{/each}}
88
- </div>
89
- {{/inline}}
1
+ <div class="section section--suite-breakdown">
2
+ <h2>Suite Breakdown</h2>
3
+ {{#if (and overflowFailureCount sections.failureDeepDive)}}
4
+ <div class="overflow-banner">
5
+ Inline failure detail covers the first {{failures.length}} failures.
6
+ {{overflowFailureCount}} more {{#if (gt overflowFailureCount 1)}}are{{else}}is{{/if}}
7
+ available in <code>{{overflowSidecarName}}</code> alongside this report.
8
+ </div>
9
+ {{/if}}
10
+ {{#each projects}}
11
+ <h3 style="color:var(--primary,#CC785C);margin-bottom:8px;">{{name}}</h3>
12
+ {{#each suites}}
13
+ {{> suite-node this depth=0}}
14
+ {{/each}}
15
+ {{/each}}
16
+ </div>
17
+
18
+ {{#*inline "suite-node"}}
19
+ <div class="suite-group">
20
+ <div class="suite-group__header">
21
+ <span class="suite-title">{{title}}</span>
22
+ <span class="suite-stats">
23
+ {{#if stats.passed}}<span class="badge badge--passed">{{stats.passed}}</span>{{/if}}
24
+ {{#if stats.failed}}<span class="badge badge--failed">{{stats.failed}}</span>{{/if}}
25
+ {{#if stats.timedOut}}<span class="badge badge--timedout">{{stats.timedOut}}</span>{{/if}}
26
+ {{#if stats.skipped}}<span class="badge badge--skipped">{{stats.skipped}}</span>{{/if}}
27
+ {{#if stats.flaky}}<span class="badge badge--flaky">{{stats.flaky}}</span>{{/if}}
28
+ </span>
29
+ </div>
30
+ {{#if tests.length}}
31
+ <table>
32
+ <thead>
33
+ <tr>
34
+ <th>Test</th>
35
+ <th style="width:112px;">Status</th>
36
+ <th style="width:72px;">Duration</th>
37
+ {{#if @root.options.showRetries}}<th style="width:52px;">Retries</th>{{/if}}
38
+ </tr>
39
+ </thead>
40
+ <tbody>
41
+ {{#each tests}}
42
+ <tr class="no-break{{#if failure}} test-row--has-detail{{/if}}">
43
+ <td>
44
+ <div style="font-weight:500;">{{title}}</div>
45
+ {{#if location}}<div class="test-path">{{location}}</div>{{/if}}
46
+ {{#if tags.length}}
47
+ <div style="margin-top:3px;">
48
+ {{#each tags}}<code style="font-size:8.5px;background:var(--surface-3);color:var(--text-3);padding:1px 5px;border-radius:3px;margin-right:3px;border:1px solid var(--border);">{{this}}</code>{{/each}}
49
+ </div>
50
+ {{/if}}
51
+ </td>
52
+ <td style="white-space:nowrap;">
53
+ {{statusBadge status}}{{#if slowRank}}<span class="badge badge--slow" title="Among the slowest tests">SLOW</span>{{/if}}
54
+ </td>
55
+ <td style="color:var(--text-2);font-family:'JetBrains Mono',monospace;font-size:9.5px;">{{formatDuration duration}}</td>
56
+ {{#if @root.options.showRetries}}<td style="color:var(--text-3);text-align:center;">{{retryCount}}</td>{{/if}}
57
+ </tr>
58
+ {{#if failure}}
59
+ <tr class="failure-row">
60
+ <td colspan="{{#if @root.options.showRetries}}4{{else}}3{{/if}}">
61
+ <div class="failure-detail failure-detail--{{failure.severity}}">
62
+ <div class="failure-detail__head">
63
+ <span class="failure-detail__dot"></span>
64
+ <span class="failure-detail__sev">{{failure.severity}} severity</span>
65
+ </div>
66
+ {{> failure-card failure=failure showFull=@root.options.showFullFailures showStack=@root.options.showStackTraces}}
67
+ {{#if chip}}
68
+ <div class="root-cause-chip root-cause-chip--{{chip.category}}">
69
+ <span class="root-cause-chip__tag">Root cause</span>
70
+ <span class="root-cause-chip__label">{{categoryLabel chip.category}}</span>
71
+ <span class="root-cause-chip__msg">{{chip.message}}</span>
72
+ <span class="root-cause-chip__strength">{{strengthLabel chip.strength}} match</span>
73
+ </div>
74
+ {{/if}}
75
+ </div>
76
+ </td>
77
+ </tr>
78
+ {{/if}}
79
+ {{/each}}
80
+ </tbody>
81
+ </table>
82
+ {{/if}}
83
+ {{#each suites}}
84
+ <div style="padding-left:14px;border-left:1px solid var(--border);margin:4px 8px;">
85
+ {{> suite-node this}}
86
+ </div>
87
+ {{/each}}
88
+ </div>
89
+ {{/inline}}
@@ -1,42 +1,42 @@
1
- {{#if meta.branding.watermark}}
2
- <script>
3
- document.addEventListener('DOMContentLoaded', function() {
4
- // Chromium's print-to-PDF doesn't repeat position:fixed elements per page, so a
5
- // single watermark div only ever prints on one page. Instead, measure the fully
6
- // parsed document (this listener fires after all content above is in the DOM)
7
- // and stamp one absolutely-positioned copy per page slot.
8
- //
9
- // Copies start at the suite breakdown, not page 1, so the summary/chart pages
10
- // stay clean. That section opens on a forced page break (.section--suite-breakdown
11
- // in base.css), which makes its top edge an exact page boundary — appending the
12
- // copies INSIDE it keeps each one page-centred even when print pagination pushes
13
- // in-flow content down, because the copies travel with the section rather than
14
- // being estimated against shifted content. When the section is absent (sections
15
- // override, custom templates), fall back to stamping the whole document.
16
- var text = {{{safeJsonData meta.branding.watermark}}};
17
- var pageHeightPx = {{watermarkPageHeightPx}};
18
- var anchor = document.querySelector('.section--suite-breakdown');
19
- var host = anchor || document.body;
20
- var startPx = anchor ? anchor.offsetTop : 0;
21
- // Copy count: ceil() of the measured span, NEVER padded in the anchor case — the
22
- // anchor origin is page-aligned, so ceil is exact for unshifted content and every
23
- // copy lands inside it (a padded copy would paint a blank trailing page with a
24
- // lone watermark). Print pagination can still push content one page further than
25
- // the screen measurement predicts (cards/rows refuse to split mid-way); in the
26
- // anchor case that at worst leaves the final spill-over page unstamped, which is
27
- // the cheaper failure. The body fallback keeps the +1: whole-document slack
28
- // (cover break + every section) reliably exceeds a page, so there the pad fills
29
- // a real page instead of minting an empty one.
30
- var extra = anchor ? 0 : 1;
31
- var pageCount = Math.min(500, Math.max(1, Math.ceil((document.body.scrollHeight - startPx) / pageHeightPx) + extra));
32
- for (var i = 0; i < pageCount; i++) {
33
- var el = document.createElement('div');
34
- el.className = 'watermark';
35
- el.setAttribute('aria-hidden', 'true');
36
- el.style.top = (i * pageHeightPx + pageHeightPx / 2) + 'px';
37
- el.textContent = text;
38
- host.appendChild(el);
39
- }
40
- });
41
- </script>
42
- {{/if}}
1
+ {{#if meta.branding.watermark}}
2
+ <script>
3
+ document.addEventListener('DOMContentLoaded', function() {
4
+ // Chromium's print-to-PDF doesn't repeat position:fixed elements per page, so a
5
+ // single watermark div only ever prints on one page. Instead, measure the fully
6
+ // parsed document (this listener fires after all content above is in the DOM)
7
+ // and stamp one absolutely-positioned copy per page slot.
8
+ //
9
+ // Copies start at the suite breakdown, not page 1, so the summary/chart pages
10
+ // stay clean. That section opens on a forced page break (.section--suite-breakdown
11
+ // in base.css), which makes its top edge an exact page boundary — appending the
12
+ // copies INSIDE it keeps each one page-centred even when print pagination pushes
13
+ // in-flow content down, because the copies travel with the section rather than
14
+ // being estimated against shifted content. When the section is absent (sections
15
+ // override, custom templates), fall back to stamping the whole document.
16
+ var text = {{{safeJsonData meta.branding.watermark}}};
17
+ var pageHeightPx = {{watermarkPageHeightPx}};
18
+ var anchor = document.querySelector('.section--suite-breakdown');
19
+ var host = anchor || document.body;
20
+ var startPx = anchor ? anchor.offsetTop : 0;
21
+ // Copy count: ceil() of the measured span, NEVER padded in the anchor case — the
22
+ // anchor origin is page-aligned, so ceil is exact for unshifted content and every
23
+ // copy lands inside it (a padded copy would paint a blank trailing page with a
24
+ // lone watermark). Print pagination can still push content one page further than
25
+ // the screen measurement predicts (cards/rows refuse to split mid-way); in the
26
+ // anchor case that at worst leaves the final spill-over page unstamped, which is
27
+ // the cheaper failure. The body fallback keeps the +1: whole-document slack
28
+ // (cover break + every section) reliably exceeds a page, so there the pad fills
29
+ // a real page instead of minting an empty one.
30
+ var extra = anchor ? 0 : 1;
31
+ var pageCount = Math.min(500, Math.max(1, Math.ceil((document.body.scrollHeight - startPx) / pageHeightPx) + extra));
32
+ for (var i = 0; i < pageCount; i++) {
33
+ var el = document.createElement('div');
34
+ el.className = 'watermark';
35
+ el.setAttribute('aria-hidden', 'true');
36
+ el.style.top = (i * pageHeightPx + pageHeightPx / 2) + 'px';
37
+ el.textContent = text;
38
+ host.appendChild(el);
39
+ }
40
+ });
41
+ </script>
42
+ {{/if}}
@@ -188,7 +188,7 @@ tr:last-child td { border-bottom: none; }
188
188
  blocks below stay glued together, and headings stick to the content beneath. */
189
189
  .section { margin-bottom: 24px; }
190
190
  .kpi-strip, .summary-row, .charts-grid, .release-gate, .flaky-callout,
191
- .trend-card, .flakiness-card, .env-grid {
191
+ .trend-card, .flakiness-card, .env-grid, .run-diff__head {
192
192
  page-break-inside: avoid; break-inside: avoid;
193
193
  }
194
194
  h2, h3 { page-break-after: avoid; break-after: avoid; }
@@ -684,6 +684,24 @@ code {
684
684
  color: var(--text-1); line-height: 1.55;
685
685
  }
686
686
 
687
+ /* ── Run diff — since-last-run counts + optional lists (sections.runDiff) ── */
688
+ .run-diff__strip { font-size: 10.5px; }
689
+ .run-diff__count strong { font-weight: 700; }
690
+ .run-diff__count--new strong { color: var(--fail); }
691
+ .run-diff__count--fixed strong { color: var(--pass); }
692
+ .run-diff__count--still strong,
693
+ .run-diff__count--neutral strong { color: var(--text-3); }
694
+ .run-diff__baseline { font-size: 9.5px; color: var(--text-3); margin-top: 4px; }
695
+ .run-diff__caveat { margin-top: 8px; }
696
+ .run-diff__list { margin-top: 10px; }
697
+ .run-diff__list-label {
698
+ font-size: 9px; font-weight: 600; letter-spacing: 0.6px; text-transform: uppercase;
699
+ color: var(--text-2); margin-bottom: 4px;
700
+ }
701
+ .run-diff__list-item { font-size: 10px; color: var(--text-1); padding: 1px 0; }
702
+ .run-diff__list-more { font-size: 9.5px; color: var(--text-3); padding: 1px 0; }
703
+ .run-diff__footnote { font-size: 9.5px; color: var(--text-3); margin-top: 8px; }
704
+
687
705
  /* Charts grid + cards (available to any template via sections.charts) */
688
706
  .charts-grid {
689
707
  display: grid; grid-template-columns: 210px 1fr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reportforge/playwright-pdf",
3
- "version": "0.24.0",
3
+ "version": "0.26.1",
4
4
  "description": "Playwright Test reporter that generates designed PDF reports: minimal, detailed, and executive templates with CI/CD integrations",
5
5
  "license": "Elastic-2.0",
6
6
  "author": "ReportForge",
@@ -86,7 +86,6 @@
86
86
  "dependencies": {
87
87
  "@cantoo/pdf-lib": "^2.7.4",
88
88
  "chrome-finder": "^1.0.7",
89
- "framer-motion": "^12.40.0",
90
89
  "glob": "^13.0.6",
91
90
  "handlebars": "^4.7.8",
92
91
  "sharp": "^0.35.3",