@reportforge/playwright-pdf 0.24.0 → 0.25.0
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 +3 -3
- package/ci-templates/azure-devops/azure-pipelines.yml +58 -58
- package/ci-templates/github-actions/basic-workflow.yml +44 -44
- package/ci-templates/gitlab-ci/.gitlab-ci.yml +42 -42
- package/ci-templates/jenkins/Jenkinsfile +54 -54
- package/dist/cli/index.js +0 -0
- package/dist/index.js +230 -9
- package/dist/index.mjs +230 -9
- package/dist/templates/layouts/detailed.hbs +41 -41
- package/dist/templates/layouts/executive.hbs +41 -41
- package/dist/templates/layouts/minimal.hbs +41 -41
- package/dist/templates/partials/analysis-oneliner.hbs +3 -3
- package/dist/templates/partials/chart-summary-grid.hbs +40 -40
- package/dist/templates/partials/chart-trend-card.hbs +16 -16
- package/dist/templates/partials/charts.hbs +433 -433
- package/dist/templates/partials/ci-environment.hbs +56 -56
- package/dist/templates/partials/cover-page.hbs +48 -48
- package/dist/templates/partials/defect-log.hbs +79 -79
- package/dist/templates/partials/executive-hero-summary.hbs +66 -66
- package/dist/templates/partials/executive-summary.hbs +78 -78
- package/dist/templates/partials/failure-card.hbs +35 -35
- package/dist/templates/partials/head.hbs +17 -17
- package/dist/templates/partials/release-gate.hbs +84 -84
- package/dist/templates/partials/requirements-matrix.hbs +51 -51
- package/dist/templates/partials/suite-breakdown.hbs +89 -89
- package/dist/templates/partials/watermark.hbs +42 -42
- 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}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reportforge/playwright-pdf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
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",
|