@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 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 (live runs and step trees are Node.js-only today)
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. Live runs and step trees are Node.js-only today. Full guide: [reportforge.org/docs/python](https://reportforge.org/docs/python).
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; live runs and step trees are Node.js-only today. Full guide: [reportforge.org/docs/dotnet](https://reportforge.org/docs/dotnet).
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
- **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, 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.
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