@reportforge/playwright-pdf 0.29.0 → 0.31.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 +11 -5
- package/dist/cli/index.js +16 -2
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +160 -72
- package/dist/index.mjs +166 -78
- package/dist/templates/partials/charts.hbs +9 -1
- package/dist/templates/partials/defect-log.hbs +2 -2
- package/dist/templates/partials/run-diff.hbs +2 -1
- package/dist/templates/styles/base.css +31 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -63,12 +63,12 @@ Three templates, one reporter. Every PDF is fully offline: fonts, charts, and sc
|
|
|
63
63
|
- **Offline failure analysis**: sorts each failure into one of 7 root-cause buckets and renders a root-cause chip under each failed test in the `detailed` PDF (dominant-cause one-liner in `executive`). No network, no AI service: a small embedded classifier with automatic updates; pin it any time. Full details at [reportforge.org/docs/advanced/failure-analysis](https://reportforge.org/docs/advanced/failure-analysis).
|
|
64
64
|
- **On-device training**: teach the classifier your team's failures without any data leaving your machine. Label locally-collected samples (`npx @reportforge/playwright-pdf label-feedback`), then `train-model` trains and cross-validates a personal layer on-device; it activates only when it measurably beats the base model on your own labeled set (`evaluate-model` shows the comparison any time). Commit the model file to your repo via `failureAnalysis.localModelPath` to share it with CI. Training data, the trained model, and evaluation are all local files; the analysis code cannot even name a network primitive (enforced by an automated source audit).
|
|
65
65
|
- `npx @reportforge/playwright-pdf export-feedback`: merges your locally-collected feedback (tokenized + redacted) into one CSV for review or moving between machines. Local file only; there is no upload.
|
|
66
|
-
- **Rich execution capture**: opt-in "Steps to Reproduce" outline (a nested, copy-pasteable Markdown list of your `test.step`s and assertions; add `apiSteps` for the full click/fill/check trail), Node console tail, and trace/video links under each failed test in the defect log. Read straight from the Playwright step tree: no fixtures, no test-code changes. Enable via `capture` (`steps` / `apiSteps` / `console` / `evidence`); off by default.
|
|
66
|
+
- **Rich execution capture**: opt-in "Steps to Reproduce" outline (a nested, copy-pasteable Markdown list of your `test.step`s and assertions; add `apiSteps` for the full click/fill/check trail), Node console tail, and trace/video links under each failed test in the defect log. Read straight from the Playwright step tree: no fixtures, no test-code changes. Enable via `capture` (`steps` / `apiSteps` / `console` / `evidence`); off by default. Set `evidenceUrlTemplate` to turn those trace/video paths into clickable CI artifact links with a QR code beside each one, so even a printed report jumps straight to the trace viewer.
|
|
67
67
|
- **Configurable sections**: add or remove any report section per template via `sections`.
|
|
68
68
|
- **Executive report brief band**: leads with a plain-language brief (trend + root causes) and one hero pass-rate number instead of a flat KPI grid
|
|
69
69
|
- **Data protection**: AES-256 password-protected PDFs (no external tools) and opt-in redaction of credentials/PII in report content and live streams
|
|
70
70
|
- **Hybrid licensing**: one short key unlocks it; reports keep rendering offline via a locally cached license between refreshes
|
|
71
|
-
- **Python and .NET support**: the same reports for pytest-playwright (`reportforge-playwright-pdf` on PyPI) and for NUnit/MSTest/xUnit (`ReportForge.Playwright.Pdf` on NuGet); one subscription key covers every ecosystem
|
|
71
|
+
- **Python and .NET support**: the same reports for pytest-playwright (`reportforge-playwright-pdf` on PyPI) and for NUnit/MSTest/xUnit (`ReportForge.Playwright.Pdf` on NuGet); one subscription key covers every ecosystem, and live runs stream from all three (step trees are Node.js-only today)
|
|
72
72
|
- **Update notice**: when a newer reporter version is published, each run ends with one info line naming it and the update command; no extra network calls
|
|
73
73
|
|
|
74
74
|
---
|
|
@@ -180,7 +180,7 @@ template = "detailed"
|
|
|
180
180
|
outputFile = "reports/{date}-{branch}-report.pdf"
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
The plugin reuses the Node runtime and Chromium that Playwright for Python already ships, so there is nothing else to install. pytest-xdist and pytest-rerunfailures are supported; failure screenshots from `--screenshot only-on-failure` are embedded. Passing `--browser` more than once splits the report into one project per browser and unlocks the cross-browser comparison section.
|
|
183
|
+
The plugin reuses the Node runtime and Chromium that Playwright for Python already ships, so there is nothing else to install. pytest-xdist and pytest-rerunfailures are supported; failure screenshots from `--screenshot only-on-failure` are embedded, and trace/video artifacts from `--tracing` / `--video` feed the defect log's evidence links (pair with `evidenceUrlTemplate` for clickable CI links). Passing `--browser` more than once splits the report into one project per browser and unlocks the cross-browser comparison section. Enable `[tool.reportforge.live] enabled = true` and the run streams to a shareable watch page, same as Node.js; step trees stay Node.js-only today. Full guide: [reportforge.org/docs/python](https://reportforge.org/docs/python).
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
@@ -195,7 +195,7 @@ set RF_LICENSE_KEY=RFSU-XXXX-XXXX-XXXX-XXXX
|
|
|
195
195
|
dotnet test --logger "reportforge;output=reports/run.pdf;template=detailed"
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
Full options come from a JSON file with the same camelCase names as this reporter: `--logger "reportforge;optionsFile=rf-options.json"`. The logger reuses the Node runtime Microsoft.Playwright places in your test output and a Playwright-managed Chromium, so there is nothing else to install. Retried tests render as flaky with their attempt history; categories become tags. A `dotnet test` run drives one browser, so the cross-browser comparison section stays hidden here
|
|
198
|
+
Full options come from a JSON file with the same camelCase names as this reporter: `--logger "reportforge;optionsFile=rf-options.json"`. The logger reuses the Node runtime Microsoft.Playwright places in your test output and a Playwright-managed Chromium, so there is nothing else to install. Retried tests render as flaky with their attempt history; categories become tags. Trace archives and videos attached via `TestContext.AddTestAttachment` feed the defect log's evidence links (pair with `evidenceUrlTemplate` for clickable CI links). A `dotnet test` run drives one browser, so the cross-browser comparison section stays hidden here. Add `"live": { "enabled": true }` to the options file and the run streams to a shareable watch page (rows appear as tests finish); step trees stay Node.js-only today. Full guide: [reportforge.org/docs/dotnet](https://reportforge.org/docs/dotnet).
|
|
199
199
|
|
|
200
200
|
---
|
|
201
201
|
|
|
@@ -253,6 +253,8 @@ All options are the second element of the reporter tuple.
|
|
|
253
253
|
| `showTrend` | `boolean` | `true` | Show the pass-rate sparkline and delta badge in the `detailed` template. Set to `false` to disable history tracking entirely. |
|
|
254
254
|
| `remoteHistory` | `boolean` | `false` | Opt-in server-side trend store so the pass-rate trend survives ephemeral CI runners (the local history file is wiped with the workspace, leaving the chart stuck at one data point). One small authenticated request per run carrying aggregate numbers only — no test titles, no error text, and the branch name never travels in plaintext. Falls back to the local history file on any failure. See the History docs. |
|
|
255
255
|
| `flakinessTopN` | `number` | `5` | Maximum flaky tests to show in the flakiness table (`detailed` template). Set to `0` to disable the table entirely. |
|
|
256
|
+
| `quarantineThreshold` | `number` | `40` | Flake-rate percentage (0-100) at which a test gets a QUARANTINE chip in the flakiness table, plus a callout with the candidate count. Applies once a test has 3+ history runs with flakiness data. Set to `0` to disable flagging. |
|
|
257
|
+
| `evidenceUrlTemplate` | `string` | n/a | URL template that turns local trace/video artifact paths (from `capture.evidence`) into clickable CI links with a QR code in the defect log. Must contain `{path}`, replaced with the forward-slashed artifact path, e.g. `https://ci.example.com/job/123/artifacts/{path}`. Unset = plain paths as before. |
|
|
256
258
|
| `slowTestThreshold` | `number` | `10` | Minimum timed-test count before `SLOW` badges appear in the suite breakdown: below this, every test is trivially the "slowest" so badges stay hidden. On larger runs only genuine outliers (at least 2× the median test duration) are badged, so the badge stays rare. Set to `0` to drop the run-size gate (outliers still required). |
|
|
257
259
|
| `requirementTagPattern` | `string` | `'^@?[A-Z][A-Z0-9]*-\\d+$'` | Regex deciding which tags count as requirement IDs in the Requirements Traceability section (`detailed` template). Matching tags (ticket shapes like `@ODP-5328`, `REQ-001`) get the traceability matrix; everything else (`@regression`, `@sanity`) collapses into a compact tag summary instead of repeating identical rows. Set to `''` to disable the split and list every tag in the matrix. |
|
|
258
260
|
| `templatePath` | `string \| string[]` | n/a | Path to a custom Handlebars (`.hbs`) template file. Takes precedence over `template`. Pass an array to generate one PDF per custom template. See the Custom Templates docs. |
|
|
@@ -286,6 +288,8 @@ reporter: [
|
|
|
286
288
|
|
|
287
289
|
Sharded runs need no extra config: every shard of one CI run converges on the same live view automatically. Set `RF_LIVE_RUN_ID` to override when your CI is not auto-detected.
|
|
288
290
|
|
|
291
|
+
**Python and .NET stream too.** Enable live the same way (`[tool.reportforge.live] enabled = true` in `pyproject.toml`, or `"live": { "enabled": true }` in the .NET options file) with `RF_LICENSE_KEY` set, and the run prints the same watch link and streams per-test progress to the same page. pytest rows appear as tests start and finish; .NET's test platform reports results only on completion, so rows appear as each test finishes. Adapter runs are single-shard: parallel CI matrix jobs in one workflow should set a distinct `RF_LIVE_RUN_ID` per job so each gets its own watch page. The live step trail and console streaming remain Node.js-only.
|
|
292
|
+
|
|
289
293
|
Live streaming is best-effort and entitlement-gated: if the server is unreachable the run is unaffected, and an active subscription with the `live` feature is required. If you've configured Slack/Teams/Discord notifications, the watch link is also posted to those channels when the run starts.
|
|
290
294
|
|
|
291
295
|
> **Security:** the watch link exposes test titles, statuses, step titles, and failure details (error messages, code frames, stacks) to anyone holding it — no login needed, which is the point: share it with whoever should watch. Your `redact` rules apply to everything on the link, error text included. The token is scoped to that one run, and rotating your license key never breaks an already-shared link. Leaving `console: false` is recommended: enabling it streams your tests' stdout/stderr to anyone holding the link. Full details at [reportforge.org/docs/advanced/live](https://reportforge.org/docs/advanced/live).
|
|
@@ -409,7 +413,9 @@ Full details at [reportforge.org/docs/advanced/security](https://reportforge.org
|
|
|
409
413
|
|
|
410
414
|
After each run the reporter appends a summary entry to a local JSON file and renders a pass-rate sparkline + verdict row in the `detailed` template.
|
|
411
415
|
|
|
412
|
-
**
|
|
416
|
+
**Flaky intelligence**: the flakiness table (`detailed` template) flags quarantine candidates — tests whose flake rate reaches `quarantineThreshold` (default 40%) across 3+ recorded runs get a QUARANTINE chip and a callout with the candidate count, and every row shows its current streak (consecutive latest runs flaky). Set `quarantineThreshold: 0` to turn flagging off.
|
|
417
|
+
|
|
418
|
+
**Since Last Run**: every report also gets a section (`runDiff`, on by default in all three templates) comparing the current run against the previous run on the same branch: new failures, newly flaky tests, fixed tests, and tests still failing, with the same summary line carried into Slack, Teams, Discord, and email notifications. The first run after upgrading has no comparable prior run to diff against, so the section starts appearing from the second run onward. It reads only the local history file, so test names never leave your machine; see the ephemeral-CI note below for keeping that file around between runs. Like the flakiness table, it rides history tracking (`showTrend`, on by default), and the notification line follows history availability rather than the `runDiff` section toggle.
|
|
413
419
|
|
|
414
420
|
**Local dev (zero config)**: history is written automatically to `~/.reportforge/{projectKey}/history.json`. The sparkline appears once two or more runs have been recorded.
|
|
415
421
|
|
package/dist/cli/index.js
CHANGED
|
@@ -293,20 +293,26 @@ function buildDemoCharts(passed, failed, skipped, flaky, total) {
|
|
|
293
293
|
delta: 71 - 76
|
|
294
294
|
// -5 vs previous run
|
|
295
295
|
},
|
|
296
|
+
flakinessQuarantineTotal: 1,
|
|
297
|
+
flakinessQuarantineThreshold: 40,
|
|
296
298
|
flakinessTable: [
|
|
297
299
|
{
|
|
298
300
|
title: "should handle session timeout gracefully",
|
|
299
301
|
flakeRate: 60,
|
|
300
302
|
flakeCount: 3,
|
|
301
303
|
totalRuns: 5,
|
|
302
|
-
sparkline: [true, false, true, false, true]
|
|
304
|
+
sparkline: [true, false, true, false, true],
|
|
305
|
+
streak: 1,
|
|
306
|
+
quarantine: true
|
|
303
307
|
},
|
|
304
308
|
{
|
|
305
309
|
title: "should apply valid promo code",
|
|
306
310
|
flakeRate: 20,
|
|
307
311
|
flakeCount: 1,
|
|
308
312
|
totalRuns: 5,
|
|
309
|
-
sparkline: [false, false, false, true, false]
|
|
313
|
+
sparkline: [false, false, false, true, false],
|
|
314
|
+
streak: 0,
|
|
315
|
+
quarantine: false
|
|
310
316
|
}
|
|
311
317
|
]
|
|
312
318
|
};
|
|
@@ -320,6 +326,9 @@ function buildDemoRunDiff() {
|
|
|
320
326
|
stillFailing: [
|
|
321
327
|
{ id: "co-3", title: "should reject expired promo code" }
|
|
322
328
|
],
|
|
329
|
+
newlyFlaky: [
|
|
330
|
+
{ id: "auth-4", title: "should handle session timeout gracefully" }
|
|
331
|
+
],
|
|
323
332
|
fixed: [
|
|
324
333
|
{ id: "co-5", title: "should complete Stripe checkout" }
|
|
325
334
|
],
|
|
@@ -6381,6 +6390,7 @@ var init_defaults = __esm({
|
|
|
6381
6390
|
historySize: 10,
|
|
6382
6391
|
showTrend: true,
|
|
6383
6392
|
flakinessTopN: 5,
|
|
6393
|
+
quarantineThreshold: 40,
|
|
6384
6394
|
slowTestThreshold: 10,
|
|
6385
6395
|
// Ticket-ID shape: @ODP-5328, REQ-001, JIRA-123. Tags matching this land in
|
|
6386
6396
|
// the Requirements Traceability matrix; the rest fall to the tag summary.
|
|
@@ -12250,6 +12260,10 @@ var init_schema = __esm({
|
|
|
12250
12260
|
// local history file is wiped every run. Aggregate numbers only.
|
|
12251
12261
|
remoteHistory: external_exports.boolean().default(false),
|
|
12252
12262
|
flakinessTopN: external_exports.number().int().min(0, "flakinessTopN must be 0 or greater").optional().default(DEFAULT_OPTIONS.flakinessTopN),
|
|
12263
|
+
quarantineThreshold: external_exports.number().int().min(0, "quarantineThreshold must be between 0 and 100").max(100, "quarantineThreshold must be between 0 and 100").optional().default(DEFAULT_OPTIONS.quarantineThreshold),
|
|
12264
|
+
evidenceUrlTemplate: external_exports.string().refine((s) => s.includes("{path}"), {
|
|
12265
|
+
message: "evidenceUrlTemplate must contain the {path} token"
|
|
12266
|
+
}).optional(),
|
|
12253
12267
|
slowTestThreshold: external_exports.number().int().min(0, "slowTestThreshold must be 0 or greater").optional().default(DEFAULT_OPTIONS.slowTestThreshold),
|
|
12254
12268
|
requirementTagPattern: external_exports.string().refine((v) => {
|
|
12255
12269
|
try {
|
package/dist/index.d.mts
CHANGED
|
@@ -368,6 +368,24 @@ interface ReporterOptions {
|
|
|
368
368
|
* @default 5
|
|
369
369
|
*/
|
|
370
370
|
flakinessTopN?: number;
|
|
371
|
+
/**
|
|
372
|
+
* Flake-rate percentage (0-100) at which a test is flagged as a quarantine
|
|
373
|
+
* candidate in the flakiness table: a QUARANTINE chip on the row plus a
|
|
374
|
+
* callout with the candidate count. A test qualifies once its flake rate
|
|
375
|
+
* over the stored history reaches the threshold across at least 3 runs
|
|
376
|
+
* that carry flakiness data. Set to 0 to disable flagging.
|
|
377
|
+
* @default 40
|
|
378
|
+
*/
|
|
379
|
+
quarantineThreshold?: number;
|
|
380
|
+
/**
|
|
381
|
+
* URL template that turns local trace/video artifact paths (surfaced by
|
|
382
|
+
* `capture.evidence`) into clickable CI links with a QR code in the defect
|
|
383
|
+
* log. Must contain the `{path}` token, replaced with the forward-slashed
|
|
384
|
+
* artifact path (each segment percent-encoded), e.g.
|
|
385
|
+
* `https://ci.example.com/job/123/artifacts/{path}`.
|
|
386
|
+
* Unset = evidence renders as plain paths, exactly as before.
|
|
387
|
+
*/
|
|
388
|
+
evidenceUrlTemplate?: string;
|
|
371
389
|
/**
|
|
372
390
|
* Minimum number of timed tests before `SLOW` badges appear in the suite
|
|
373
391
|
* breakdown — below this, every test is trivially the "slowest", so badges
|
package/dist/index.d.ts
CHANGED
|
@@ -368,6 +368,24 @@ interface ReporterOptions {
|
|
|
368
368
|
* @default 5
|
|
369
369
|
*/
|
|
370
370
|
flakinessTopN?: number;
|
|
371
|
+
/**
|
|
372
|
+
* Flake-rate percentage (0-100) at which a test is flagged as a quarantine
|
|
373
|
+
* candidate in the flakiness table: a QUARANTINE chip on the row plus a
|
|
374
|
+
* callout with the candidate count. A test qualifies once its flake rate
|
|
375
|
+
* over the stored history reaches the threshold across at least 3 runs
|
|
376
|
+
* that carry flakiness data. Set to 0 to disable flagging.
|
|
377
|
+
* @default 40
|
|
378
|
+
*/
|
|
379
|
+
quarantineThreshold?: number;
|
|
380
|
+
/**
|
|
381
|
+
* URL template that turns local trace/video artifact paths (surfaced by
|
|
382
|
+
* `capture.evidence`) into clickable CI links with a QR code in the defect
|
|
383
|
+
* log. Must contain the `{path}` token, replaced with the forward-slashed
|
|
384
|
+
* artifact path (each segment percent-encoded), e.g.
|
|
385
|
+
* `https://ci.example.com/job/123/artifacts/{path}`.
|
|
386
|
+
* Unset = evidence renders as plain paths, exactly as before.
|
|
387
|
+
*/
|
|
388
|
+
evidenceUrlTemplate?: string;
|
|
371
389
|
/**
|
|
372
390
|
* Minimum number of timed tests before `SLOW` badges appear in the suite
|
|
373
391
|
* breakdown — below this, every test is trivially the "slowest", so badges
|