@reportforge/playwright-pdf 0.8.1 → 0.10.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
@@ -53,6 +53,7 @@ Three templates, one reporter. Every PDF is fully offline — fonts, charts, and
53
53
  - **Dynamic filenames** — `{date}`, `{branch}`, `{status}` tokens in the output path
54
54
  - **Instant demo report** — `npx @reportforge/playwright-pdf demo` generates a realistic sample PDF before subscribing — no license key required
55
55
  - **CI/CD snippets** — GitHub Actions, GitLab CI, Bitbucket Pipelines, Jenkins, Azure DevOps
56
+ - **Live runs** — opt-in `live` streams per-test progress to an unguessable watch link printed at run start; all shards of one CI run converge on a single live dashboard while tests execute. The PDF is still produced at the end, unchanged
56
57
  - **Shard merging** — combine N Playwright JSON shard reports into one PDF via `shardResults`; accepts glob patterns or explicit paths
57
58
  - **Notifications** — post pass/fail summaries to Slack, Teams, Discord, or email after each run; configurable trigger (`always` / `failure` / `success`) per channel; email supports optional PDF attachment via `attachPdf`
58
59
  - **Flakiness trend** — top-N flakiest tests table with per-test dot sparkline across stored history runs in the `detailed` template; `flakinessTopN` option (default 5, `0` disables)
@@ -196,6 +197,7 @@ All options are the second element of the reporter tuple.
196
197
  | `notify` | `object` | — | Notification channels: `slack`, `teams`, `discord` (each `{ url, enabled, on }`), `email` (`{ to, enabled, on, attachPdf }`). See the Notifications docs. |
197
198
  | `failureAnalysis` | `object` | `{ enabled: true }` | Offline failure root-cause analysis (embedded Naive Bayes; no runtime network). Fields: `enabled` (default `true`), `maxClusters` (default `10`), `minStrength` (`weak`\|`moderate`\|`strong`, default `weak`), `maxFailuresToAnalyse` (default `500`), `collectUnclassified` (default `true`), `autoUpdateModel` (default `true`). See the Failure Analysis docs. |
198
199
  | `capture` | `object` | `{}` (off) | Opt-in rich execution capture for the defect log (reporter-side; no fixtures, no test-code changes). Fields: `steps` (compacted repro-steps trail from the Playwright step tree, default `false`), `apiSteps` (include granular `pw:api` click/fill/goto actions in the trail; off by default the trail shows only `test.step` intent + `expect` assertions + the failing action, default `false`), `console` (Node stdout/stderr tail, default `false`), `evidence` (trace/video file links, default `false`), `maxSteps` (default `50`), `maxConsoleLines` (default `50`). Renders in the Defect Log section of the `detailed` template. |
200
+ | `live` | `object` | `{}` (off) | Opt-in live test-execution streaming. When `enabled`, the reporter prints an unguessable watch link to the CI logs at run start and streams per-test progress to the hosted dashboard while tests run — all shards of one CI run converge on a single live view. Fields: `enabled` (default `false`), `runId` (override the auto-derived run id), `serverUrl` (override the streaming server), `steps` (`none`\|`failed`\|`all`, default `failed`), `console` (stream stdout/stderr tails, default `false`), `flushMs` (batch debounce 500–10000, default `2000`). The PDF at the end of the run is unaffected. Requires an active subscription with the `live` entitlement. See the Live Runs docs. |
199
201
  | `historyFile` | `string` | `~/.reportforge/{key}/history.json` | Path to the history JSON file. Relative paths resolve from `cwd`. Enables pass-rate trending charts in the `detailed` template. |
200
202
  | `historySize` | `number` | `10` | Maximum number of test runs to keep in the history file (integer ≥ 2). Older runs are pruned on append. |
201
203
  | `showTrend` | `boolean` | `true` | Show the pass-rate sparkline and delta badge in the `detailed` template. Set to `false` to disable history tracking entirely. |
@@ -207,6 +209,31 @@ All options are the second element of the reporter tuple.
207
209
 
208
210
  Full reference: [reportforge.org/docs/configuration](https://reportforge.org/docs/configuration).
209
211
 
212
+ ### Live Runs
213
+
214
+ Watch a run as it happens. With `live` enabled, the reporter prints an unguessable watch link — boxed under a `Live Tracker` heading — to your CI logs at run start and streams per-test progress to a hosted dashboard while tests execute. All shards of one CI run converge on a single live view, each running test shows the step it's currently executing, and the PDF is still generated at the end, unchanged.
215
+
216
+ ```typescript
217
+ // playwright.config.ts
218
+ reporter: [
219
+ ['@reportforge/playwright-pdf', {
220
+ outputFile: 'reports/{date}-report.pdf',
221
+ live: {
222
+ enabled: true,
223
+ steps: 'failed', // 'none' | 'failed' | 'all'
224
+ // console: false, // stream stdout/stderr tails (off by default — see note)
225
+ // flushMs: 2000, // batch debounce (500–10000)
226
+ },
227
+ }],
228
+ ],
229
+ ```
230
+
231
+ Sharded runs need no extra config — the run id is derived from the run-shared CI identifier (e.g. `GITHUB_RUN_ID`), identical across every matrix shard. Set `RF_LIVE_RUN_ID` to override when your CI is not auto-detected.
232
+
233
+ 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.
234
+
235
+ > **Security:** the watch link exposes test titles + statuses (and step titles when `steps` is on). 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).
236
+
210
237
  ### Shard Merging
211
238
 
212
239
  Combine parallel Playwright shards into one PDF without re-running any tests.
@@ -629,6 +656,7 @@ Full documentation at [reportforge.org/docs](https://reportforge.org/docs):
629
656
  - [Configuration reference](https://reportforge.org/docs/configuration) — all options
630
657
  - [Filename tokens](https://reportforge.org/docs/configuration#tokens) — `{date}`, `{branch}`, `{status}`
631
658
  - [Templates](https://reportforge.org/docs/templates) — minimal, detailed, executive
659
+ - [Live runs](https://reportforge.org/docs/advanced/live) — stream per-test progress to a shared watch link
632
660
  - [Report Sections](https://reportforge.org/docs/configuration#report-sections) — add or remove sections per template
633
661
  - [License & offline behaviour](https://reportforge.org/docs/licensing) — JWT cache, machine cap, cancellation
634
662
  - [Troubleshooting](https://reportforge.org/docs/troubleshooting) — common issues and debug flags
package/dist/cli/index.js CHANGED
@@ -11831,7 +11831,7 @@ ${issues}`);
11831
11831
  }
11832
11832
  return result.data;
11833
11833
  }
11834
- var hexColor, channelConfigSchema, emailChannelConfigSchema, notifyConfigSchema, failureAnalysisConfigSchema, captureConfigSchema, sectionFlagsShape, sectionFlagsSchema, sectionsSchema, ReporterOptionsSchema;
11834
+ var hexColor, channelConfigSchema, emailChannelConfigSchema, notifyConfigSchema, failureAnalysisConfigSchema, captureConfigSchema, liveConfigSchema, sectionFlagsShape, sectionFlagsSchema, sectionsSchema, ReporterOptionsSchema;
11835
11835
  var init_schema = __esm({
11836
11836
  "src/config/schema.ts"() {
11837
11837
  "use strict";
@@ -11878,6 +11878,21 @@ var init_schema = __esm({
11878
11878
  maxSteps: external_exports.number().int().min(1).max(500).default(50),
11879
11879
  maxConsoleLines: external_exports.number().int().min(1).max(1e3).default(50)
11880
11880
  }).default({});
11881
+ liveConfigSchema = external_exports.object({
11882
+ enabled: external_exports.boolean().default(false),
11883
+ // Override the auto-derived run id. All shards of one run must share it.
11884
+ runId: external_exports.string().optional(),
11885
+ // Override the streaming/server base URL (defaults to the license serverUrl).
11886
+ serverUrl: external_exports.string().url().optional(),
11887
+ // Step verbosity: 'none' skips steps, 'failed' streams intent + assertions +
11888
+ // errored steps, 'all' streams every step.
11889
+ steps: external_exports.enum(["none", "failed", "all"]).default("failed"),
11890
+ // Stream test stdout/stderr tails. Off by default — may leak secrets printed
11891
+ // by tests to a token-holder.
11892
+ console: external_exports.boolean().default(false),
11893
+ // Debounce window for batched flushes (ms).
11894
+ flushMs: external_exports.number().int().min(500).max(1e4).default(2e3)
11895
+ }).default({});
11881
11896
  sectionFlagsShape = Object.fromEntries(
11882
11897
  SECTION_KEYS.map((k) => [k, external_exports.boolean().optional()])
11883
11898
  );
@@ -11919,6 +11934,7 @@ var init_schema = __esm({
11919
11934
  slowTestThreshold: external_exports.number().int().min(0, "slowTestThreshold must be 0 or greater").optional().default(DEFAULT_OPTIONS.slowTestThreshold),
11920
11935
  failureAnalysis: failureAnalysisConfigSchema,
11921
11936
  capture: captureConfigSchema,
11937
+ live: liveConfigSchema,
11922
11938
  templatePath: external_exports.union([
11923
11939
  external_exports.string().regex(/\.hbs$/, "templatePath must end with .hbs").refine((v) => v.slice(0, -4).trim().length > 0, "templatePath basename must not be empty"),
11924
11940
  external_exports.array(
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
1
+ import { Reporter, FullConfig, Suite, TestCase, TestResult, TestStep, FullResult } from '@playwright/test/reporter';
2
2
 
3
3
  /**
4
4
  * Canonical section catalog. 13 block toggles (section present/absent) followed
@@ -237,6 +237,38 @@ interface ReporterOptions {
237
237
  /** Max console lines retained per stream. Default: 50 */
238
238
  maxConsoleLines?: number;
239
239
  };
240
+ /**
241
+ * Live test-execution streaming (opt-in, off by default). When enabled the
242
+ * reporter mints an unguessable watch link, prints it to the CI logs at run
243
+ * start, and streams per-test progress (and optionally per-step / console
244
+ * tails) to the hosted dashboard while your tests run. All shards of one CI
245
+ * run converge on a single live view automatically. The PDF generated at the
246
+ * end of the run is unaffected. Requires an active subscription with the
247
+ * `live` entitlement; degrades to a no-op otherwise.
248
+ *
249
+ * @example
250
+ * live: { enabled: true, steps: 'all' }
251
+ */
252
+ live?: {
253
+ /** Enable live streaming. Default: false */
254
+ enabled?: boolean;
255
+ /** Override the auto-derived run id. All shards of one run must share it. */
256
+ runId?: string;
257
+ /** Override the streaming server base URL. Defaults to the license `serverUrl`. */
258
+ serverUrl?: string;
259
+ /**
260
+ * Step verbosity: `'none'` skips steps, `'failed'` streams author intent +
261
+ * assertions + errored steps, `'all'` streams every step. Default: `'failed'`
262
+ */
263
+ steps?: 'none' | 'failed' | 'all';
264
+ /**
265
+ * Stream test stdout/stderr tails to the watch page. Off by default — may
266
+ * leak secrets printed by tests to anyone holding the watch link. Default: false
267
+ */
268
+ console?: boolean;
269
+ /** Debounce window for batched flushes, in milliseconds (500–10000). Default: 2000 */
270
+ flushMs?: number;
271
+ };
240
272
  /**
241
273
  * Path to the history JSON file. Defaults to
242
274
  * `~/.reportforge/{projectKey}/history.json` where `projectKey` is derived
@@ -330,6 +362,13 @@ interface LicenseInfo {
330
362
  jwt?: string;
331
363
  machinesUsed?: number;
332
364
  machineLimit?: number;
365
+ /**
366
+ * Entitlement flags carried on the signed JWT (`features` claim). Surfaces
367
+ * server-gated capabilities (e.g. `'live'`) to the reporter without a second
368
+ * network trip. Undefined for caches written by reporter versions before this
369
+ * field was persisted — treat absence as "no extra features".
370
+ */
371
+ features?: string[];
333
372
  }
334
373
 
335
374
  /**
@@ -371,16 +410,47 @@ declare class PdfReporter implements Reporter {
371
410
  private readonly licenseClient;
372
411
  private readonly dataCollector;
373
412
  private readonly pdfGenerator;
413
+ private licensePromise?;
414
+ private liveStreamer?;
415
+ private liveShardKey;
416
+ private liveSteps;
417
+ private liveConsole;
374
418
  constructor(rawOptions?: ReporterOptions);
375
419
  onBegin(config: FullConfig, suite: Suite): void;
420
+ onTestBegin(test: TestCase): void;
376
421
  onTestEnd(test: TestCase, result: TestResult): void;
422
+ onStepBegin(test: TestCase, _result: TestResult, step: TestStep): void;
423
+ onStepEnd(test: TestCase, _result: TestResult, step: TestStep): void;
424
+ onStdOut(chunk: string | Buffer, test?: TestCase): void;
425
+ onStdErr(chunk: string | Buffer, test?: TestCase): void;
426
+ onExit(): Promise<void>;
377
427
  onEnd(result: FullResult): Promise<void>;
378
428
  private _collectData;
379
429
  private _appendTrend;
380
430
  private _populateHistoryCharts;
381
431
  private _buildReportData;
382
432
  printsToStdio(): boolean;
433
+ /**
434
+ * Memoized license resolution shared by the live stream (kicked early in
435
+ * onBegin) and PDF generation (awaited in onEnd) — at most one network trip.
436
+ */
437
+ private license;
383
438
  private resolveLicense;
439
+ /**
440
+ * Wires up live streaming: derives the run id (shared by all shards), kicks
441
+ * the license resolution early, builds the streamer, and prints the watch
442
+ * link to the CI logs. Throws are caught by the onBegin try/catch.
443
+ */
444
+ private setupLive;
445
+ /**
446
+ * Announces the watch link once the run is confirmed live-entitled. Gating on
447
+ * the SAME resolved entitlement the streamer requires (`jwt` + the `'live'`
448
+ * feature) guarantees the link is never printed or posted for a run that will
449
+ * never stream — no dead links. The chat ping fires from the primary shard only
450
+ * (unsharded, or `shard.current === 1`) so an N-way matrix posts one message,
451
+ * not N. The banner still prints from every shard's own log.
452
+ */
453
+ private announceLive;
384
454
  private resolveProjectName;
385
455
  private openPdf;
386
456
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
1
+ import { Reporter, FullConfig, Suite, TestCase, TestResult, TestStep, FullResult } from '@playwright/test/reporter';
2
2
 
3
3
  /**
4
4
  * Canonical section catalog. 13 block toggles (section present/absent) followed
@@ -237,6 +237,38 @@ interface ReporterOptions {
237
237
  /** Max console lines retained per stream. Default: 50 */
238
238
  maxConsoleLines?: number;
239
239
  };
240
+ /**
241
+ * Live test-execution streaming (opt-in, off by default). When enabled the
242
+ * reporter mints an unguessable watch link, prints it to the CI logs at run
243
+ * start, and streams per-test progress (and optionally per-step / console
244
+ * tails) to the hosted dashboard while your tests run. All shards of one CI
245
+ * run converge on a single live view automatically. The PDF generated at the
246
+ * end of the run is unaffected. Requires an active subscription with the
247
+ * `live` entitlement; degrades to a no-op otherwise.
248
+ *
249
+ * @example
250
+ * live: { enabled: true, steps: 'all' }
251
+ */
252
+ live?: {
253
+ /** Enable live streaming. Default: false */
254
+ enabled?: boolean;
255
+ /** Override the auto-derived run id. All shards of one run must share it. */
256
+ runId?: string;
257
+ /** Override the streaming server base URL. Defaults to the license `serverUrl`. */
258
+ serverUrl?: string;
259
+ /**
260
+ * Step verbosity: `'none'` skips steps, `'failed'` streams author intent +
261
+ * assertions + errored steps, `'all'` streams every step. Default: `'failed'`
262
+ */
263
+ steps?: 'none' | 'failed' | 'all';
264
+ /**
265
+ * Stream test stdout/stderr tails to the watch page. Off by default — may
266
+ * leak secrets printed by tests to anyone holding the watch link. Default: false
267
+ */
268
+ console?: boolean;
269
+ /** Debounce window for batched flushes, in milliseconds (500–10000). Default: 2000 */
270
+ flushMs?: number;
271
+ };
240
272
  /**
241
273
  * Path to the history JSON file. Defaults to
242
274
  * `~/.reportforge/{projectKey}/history.json` where `projectKey` is derived
@@ -330,6 +362,13 @@ interface LicenseInfo {
330
362
  jwt?: string;
331
363
  machinesUsed?: number;
332
364
  machineLimit?: number;
365
+ /**
366
+ * Entitlement flags carried on the signed JWT (`features` claim). Surfaces
367
+ * server-gated capabilities (e.g. `'live'`) to the reporter without a second
368
+ * network trip. Undefined for caches written by reporter versions before this
369
+ * field was persisted — treat absence as "no extra features".
370
+ */
371
+ features?: string[];
333
372
  }
334
373
 
335
374
  /**
@@ -371,16 +410,47 @@ declare class PdfReporter implements Reporter {
371
410
  private readonly licenseClient;
372
411
  private readonly dataCollector;
373
412
  private readonly pdfGenerator;
413
+ private licensePromise?;
414
+ private liveStreamer?;
415
+ private liveShardKey;
416
+ private liveSteps;
417
+ private liveConsole;
374
418
  constructor(rawOptions?: ReporterOptions);
375
419
  onBegin(config: FullConfig, suite: Suite): void;
420
+ onTestBegin(test: TestCase): void;
376
421
  onTestEnd(test: TestCase, result: TestResult): void;
422
+ onStepBegin(test: TestCase, _result: TestResult, step: TestStep): void;
423
+ onStepEnd(test: TestCase, _result: TestResult, step: TestStep): void;
424
+ onStdOut(chunk: string | Buffer, test?: TestCase): void;
425
+ onStdErr(chunk: string | Buffer, test?: TestCase): void;
426
+ onExit(): Promise<void>;
377
427
  onEnd(result: FullResult): Promise<void>;
378
428
  private _collectData;
379
429
  private _appendTrend;
380
430
  private _populateHistoryCharts;
381
431
  private _buildReportData;
382
432
  printsToStdio(): boolean;
433
+ /**
434
+ * Memoized license resolution shared by the live stream (kicked early in
435
+ * onBegin) and PDF generation (awaited in onEnd) — at most one network trip.
436
+ */
437
+ private license;
383
438
  private resolveLicense;
439
+ /**
440
+ * Wires up live streaming: derives the run id (shared by all shards), kicks
441
+ * the license resolution early, builds the streamer, and prints the watch
442
+ * link to the CI logs. Throws are caught by the onBegin try/catch.
443
+ */
444
+ private setupLive;
445
+ /**
446
+ * Announces the watch link once the run is confirmed live-entitled. Gating on
447
+ * the SAME resolved entitlement the streamer requires (`jwt` + the `'live'`
448
+ * feature) guarantees the link is never printed or posted for a run that will
449
+ * never stream — no dead links. The chat ping fires from the primary shard only
450
+ * (unsharded, or `shard.current === 1`) so an N-way matrix posts one message,
451
+ * not N. The banner still prints from every shard's own log.
452
+ */
453
+ private announceLive;
384
454
  private resolveProjectName;
385
455
  private openPdf;
386
456
  }