@reportforge/playwright-pdf 0.8.0 → 0.8.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/dist/index.js
CHANGED
|
@@ -11407,6 +11407,7 @@ var DEFAULT_MAX_STEPS = 50;
|
|
|
11407
11407
|
var DEFAULT_MAX_CONSOLE_LINES = 50;
|
|
11408
11408
|
var PW_API_WINDOW = 10;
|
|
11409
11409
|
var isTeardown = (category) => category === "hook" || category === "fixture";
|
|
11410
|
+
var inHookSubtree = (flat, f) => isTeardown(f.category) || f.ancestors.some((a) => isTeardown(flat[a].category));
|
|
11410
11411
|
function flatten(steps) {
|
|
11411
11412
|
const out = [];
|
|
11412
11413
|
const walk = (nodes, depth, ancestors) => {
|
|
@@ -11425,7 +11426,7 @@ function flatten(steps) {
|
|
|
11425
11426
|
walk(steps ?? [], 0, []);
|
|
11426
11427
|
return out;
|
|
11427
11428
|
}
|
|
11428
|
-
function materialize(n) {
|
|
11429
|
+
function materialize(n, isFailing) {
|
|
11429
11430
|
const loc = n.raw.location;
|
|
11430
11431
|
return {
|
|
11431
11432
|
title: clampWithEllipsis(n.raw.title ?? "", MAX_TITLE_CHARS),
|
|
@@ -11433,17 +11434,16 @@ function materialize(n) {
|
|
|
11433
11434
|
durationMs: Math.max(0, Math.round(n.raw.duration ?? 0)),
|
|
11434
11435
|
depth: n.depth,
|
|
11435
11436
|
failed: n.hasError,
|
|
11436
|
-
errorMessage: n.raw.error?.message ? clampWithEllipsis(stripAnsi(n.raw.error.message).split("\n")[0], MAX_TITLE_CHARS) : void 0,
|
|
11437
|
+
errorMessage: isFailing && n.raw.error?.message ? clampWithEllipsis(stripAnsi(n.raw.error.message).split("\n")[0], MAX_TITLE_CHARS) : void 0,
|
|
11437
11438
|
location: loc?.file != null ? `${loc.file}:${loc.line ?? 0}` : void 0
|
|
11438
11439
|
};
|
|
11439
11440
|
}
|
|
11440
11441
|
function pickFailingIdx(flat) {
|
|
11441
|
-
const inTeardown = (f) => isTeardown(f.category) || f.ancestors.some((a) => isTeardown(flat[a].category));
|
|
11442
11442
|
const pick = (allowTeardown) => {
|
|
11443
11443
|
let idx = -1;
|
|
11444
11444
|
for (let i = 0; i < flat.length; i++) {
|
|
11445
11445
|
const f = flat[i];
|
|
11446
|
-
if (!f.hasError || !allowTeardown &&
|
|
11446
|
+
if (!f.hasError || !allowTeardown && inHookSubtree(flat, f)) continue;
|
|
11447
11447
|
if (idx === -1 || f.depth >= flat[idx].depth) idx = i;
|
|
11448
11448
|
}
|
|
11449
11449
|
return idx;
|
|
@@ -11466,7 +11466,7 @@ function compactSteps(rawSteps, opts = {}) {
|
|
|
11466
11466
|
if (opts.apiSteps) {
|
|
11467
11467
|
const pwApiBefore = [];
|
|
11468
11468
|
for (let i = 0; i < failingIdx; i++) {
|
|
11469
|
-
if (flat[i].category === "pw:api") pwApiBefore.push(i);
|
|
11469
|
+
if (flat[i].category === "pw:api" && !inHookSubtree(flat, flat[i])) pwApiBefore.push(i);
|
|
11470
11470
|
}
|
|
11471
11471
|
for (const i of pwApiBefore.slice(-PW_API_WINDOW)) keep.add(i);
|
|
11472
11472
|
}
|
|
@@ -11482,7 +11482,7 @@ function compactSteps(rawSteps, opts = {}) {
|
|
|
11482
11482
|
const mat = (i) => {
|
|
11483
11483
|
let es = cache.get(i);
|
|
11484
11484
|
if (!es) {
|
|
11485
|
-
es = materialize(flat[i]);
|
|
11485
|
+
es = materialize(flat[i], i === failingIdx);
|
|
11486
11486
|
cache.set(i, es);
|
|
11487
11487
|
}
|
|
11488
11488
|
return es;
|
|
@@ -13495,7 +13495,7 @@ var PdfReporter = class {
|
|
|
13495
13495
|
this.pdfGenerator = new PdfGenerator();
|
|
13496
13496
|
this.options = parseOptions(rawOptions);
|
|
13497
13497
|
this.dataCollector = new DataCollector(this.options.capture);
|
|
13498
|
-
const version = true ? "0.8.
|
|
13498
|
+
const version = true ? "0.8.1" : "0.x";
|
|
13499
13499
|
logger.info(`@reportforge/playwright-pdf v${version} initialised`);
|
|
13500
13500
|
this.licenseClient = new LicenseClient({
|
|
13501
13501
|
licenseKey: this.options.licenseKey,
|
package/dist/index.mjs
CHANGED
|
@@ -11408,6 +11408,7 @@ var DEFAULT_MAX_STEPS = 50;
|
|
|
11408
11408
|
var DEFAULT_MAX_CONSOLE_LINES = 50;
|
|
11409
11409
|
var PW_API_WINDOW = 10;
|
|
11410
11410
|
var isTeardown = (category) => category === "hook" || category === "fixture";
|
|
11411
|
+
var inHookSubtree = (flat, f) => isTeardown(f.category) || f.ancestors.some((a) => isTeardown(flat[a].category));
|
|
11411
11412
|
function flatten(steps) {
|
|
11412
11413
|
const out = [];
|
|
11413
11414
|
const walk = (nodes, depth, ancestors) => {
|
|
@@ -11426,7 +11427,7 @@ function flatten(steps) {
|
|
|
11426
11427
|
walk(steps ?? [], 0, []);
|
|
11427
11428
|
return out;
|
|
11428
11429
|
}
|
|
11429
|
-
function materialize(n) {
|
|
11430
|
+
function materialize(n, isFailing) {
|
|
11430
11431
|
const loc = n.raw.location;
|
|
11431
11432
|
return {
|
|
11432
11433
|
title: clampWithEllipsis(n.raw.title ?? "", MAX_TITLE_CHARS),
|
|
@@ -11434,17 +11435,16 @@ function materialize(n) {
|
|
|
11434
11435
|
durationMs: Math.max(0, Math.round(n.raw.duration ?? 0)),
|
|
11435
11436
|
depth: n.depth,
|
|
11436
11437
|
failed: n.hasError,
|
|
11437
|
-
errorMessage: n.raw.error?.message ? clampWithEllipsis(stripAnsi(n.raw.error.message).split("\n")[0], MAX_TITLE_CHARS) : void 0,
|
|
11438
|
+
errorMessage: isFailing && n.raw.error?.message ? clampWithEllipsis(stripAnsi(n.raw.error.message).split("\n")[0], MAX_TITLE_CHARS) : void 0,
|
|
11438
11439
|
location: loc?.file != null ? `${loc.file}:${loc.line ?? 0}` : void 0
|
|
11439
11440
|
};
|
|
11440
11441
|
}
|
|
11441
11442
|
function pickFailingIdx(flat) {
|
|
11442
|
-
const inTeardown = (f) => isTeardown(f.category) || f.ancestors.some((a) => isTeardown(flat[a].category));
|
|
11443
11443
|
const pick = (allowTeardown) => {
|
|
11444
11444
|
let idx = -1;
|
|
11445
11445
|
for (let i = 0; i < flat.length; i++) {
|
|
11446
11446
|
const f = flat[i];
|
|
11447
|
-
if (!f.hasError || !allowTeardown &&
|
|
11447
|
+
if (!f.hasError || !allowTeardown && inHookSubtree(flat, f)) continue;
|
|
11448
11448
|
if (idx === -1 || f.depth >= flat[idx].depth) idx = i;
|
|
11449
11449
|
}
|
|
11450
11450
|
return idx;
|
|
@@ -11467,7 +11467,7 @@ function compactSteps(rawSteps, opts = {}) {
|
|
|
11467
11467
|
if (opts.apiSteps) {
|
|
11468
11468
|
const pwApiBefore = [];
|
|
11469
11469
|
for (let i = 0; i < failingIdx; i++) {
|
|
11470
|
-
if (flat[i].category === "pw:api") pwApiBefore.push(i);
|
|
11470
|
+
if (flat[i].category === "pw:api" && !inHookSubtree(flat, flat[i])) pwApiBefore.push(i);
|
|
11471
11471
|
}
|
|
11472
11472
|
for (const i of pwApiBefore.slice(-PW_API_WINDOW)) keep.add(i);
|
|
11473
11473
|
}
|
|
@@ -11483,7 +11483,7 @@ function compactSteps(rawSteps, opts = {}) {
|
|
|
11483
11483
|
const mat = (i) => {
|
|
11484
11484
|
let es = cache.get(i);
|
|
11485
11485
|
if (!es) {
|
|
11486
|
-
es = materialize(flat[i]);
|
|
11486
|
+
es = materialize(flat[i], i === failingIdx);
|
|
11487
11487
|
cache.set(i, es);
|
|
11488
11488
|
}
|
|
11489
11489
|
return es;
|
|
@@ -13496,7 +13496,7 @@ var PdfReporter = class {
|
|
|
13496
13496
|
this.pdfGenerator = new PdfGenerator();
|
|
13497
13497
|
this.options = parseOptions(rawOptions);
|
|
13498
13498
|
this.dataCollector = new DataCollector(this.options.capture);
|
|
13499
|
-
const version = true ? "0.8.
|
|
13499
|
+
const version = true ? "0.8.1" : "0.x";
|
|
13500
13500
|
logger.info(`@reportforge/playwright-pdf v${version} initialised`);
|
|
13501
13501
|
this.licenseClient = new LicenseClient({
|
|
13502
13502
|
licenseKey: this.options.licenseKey,
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<th style="width:72px;text-align:right;">Duration</th>
|
|
12
12
|
</tr>
|
|
13
13
|
</thead>
|
|
14
|
-
<tbody>
|
|
15
14
|
{{#each failures}}
|
|
15
|
+
<tbody class="defect-row-group">
|
|
16
16
|
<tr class="no-break">
|
|
17
17
|
<td class="defect-id">DEF-{{addOne @index}}</td>
|
|
18
18
|
<td style="font-weight:500;">{{testTitle}}</td>
|
|
@@ -24,9 +24,14 @@
|
|
|
24
24
|
<tr class="defect-detail-row">
|
|
25
25
|
<td colspan="5">
|
|
26
26
|
<div class="defect-detail">
|
|
27
|
+
{{! Error sits at the failing step inside the trail. Only when there is no
|
|
28
|
+
identified failing step (capture.steps off, or no errored step) is it
|
|
29
|
+
shown here under the title as a fallback. }}
|
|
30
|
+
{{#unless execution.failingStep}}
|
|
27
31
|
{{#if error.message}}
|
|
28
32
|
<div class="defect-detail__error">{{error.message}}</div>
|
|
29
33
|
{{/if}}
|
|
34
|
+
{{/unless}}
|
|
30
35
|
|
|
31
36
|
{{#if execution.steps.length}}
|
|
32
37
|
<div class="repro">
|
|
@@ -38,6 +43,7 @@
|
|
|
38
43
|
<span class="repro-step__title">{{title}}</span>
|
|
39
44
|
{{#if failed}}{{#if location}}<span class="repro-step__loc">{{location}}</span>{{/if}}{{/if}}
|
|
40
45
|
<span class="repro-step__dur">{{formatDuration durationMs}}</span>
|
|
46
|
+
{{#if errorMessage}}<div class="repro-step__error">{{../error.message}}</div>{{/if}}
|
|
41
47
|
</li>
|
|
42
48
|
{{/each}}
|
|
43
49
|
</ol>
|
|
@@ -64,8 +70,8 @@
|
|
|
64
70
|
</td>
|
|
65
71
|
</tr>
|
|
66
72
|
{{/if}}
|
|
73
|
+
</tbody>
|
|
67
74
|
{{/each}}
|
|
68
|
-
</tbody>
|
|
69
75
|
</table>
|
|
70
76
|
</div>
|
|
71
77
|
{{/if}}
|
|
@@ -409,6 +409,9 @@ code {
|
|
|
409
409
|
design-system-consistent: a light bordered card (NO side rail, per the
|
|
410
410
|
side-stripe ban in DESIGN.md), with hairline dividers between sub-blocks —
|
|
411
411
|
mirroring the reworked .failure-detail and .retry-history patterns. */
|
|
412
|
+
/* Each failure is its own <tbody> so its summary row and detail card stay together
|
|
413
|
+
across a page break — the detail no longer strands under a repeated header. */
|
|
414
|
+
.defect-row-group { break-inside: avoid; page-break-inside: avoid; }
|
|
412
415
|
.defect-detail-row td { padding: 0; border-top: none; }
|
|
413
416
|
.defect-detail {
|
|
414
417
|
border: 1px solid var(--border-2);
|
|
@@ -435,12 +438,19 @@ code {
|
|
|
435
438
|
.repro { margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--border); }
|
|
436
439
|
.repro-steps { list-style: none; margin: 6px 0 0; padding: 0; }
|
|
437
440
|
.repro-step {
|
|
438
|
-
display: flex; align-items: baseline; gap: 8px;
|
|
441
|
+
display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
|
|
439
442
|
/* indent by tree depth (capped) — the value comes from `--d` on the element */
|
|
440
443
|
padding: 2px 0 2px min(60px, calc(var(--d, 0) * 12px));
|
|
441
444
|
font-size: 9px; line-height: 1.5;
|
|
442
445
|
page-break-inside: avoid; break-inside: avoid;
|
|
443
446
|
}
|
|
447
|
+
/* The error sits at the failing step — full width below its row, indented past the
|
|
448
|
+
category column so it reads as belonging to that step. */
|
|
449
|
+
.repro-step__error {
|
|
450
|
+
flex-basis: 100%; margin: 3px 0 2px; padding-left: 60px;
|
|
451
|
+
font-family: 'JetBrains Mono', monospace; font-size: 9px; line-height: 1.55;
|
|
452
|
+
color: #8A2E1E; white-space: pre-wrap; word-break: break-word;
|
|
453
|
+
}
|
|
444
454
|
.repro-step__cat {
|
|
445
455
|
flex: none; min-width: 52px;
|
|
446
456
|
font-family: 'JetBrains Mono', monospace; font-size: 8px; color: var(--text-3);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reportforge/playwright-pdf",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Enterprise-ready PDF reports for Playwright Test — minimal, detailed, and executive templates with CI/CD integrations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ReportForge",
|