@reportforge/playwright-pdf 0.2.1 → 0.2.2

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
@@ -165,31 +165,34 @@ Currency is auto-detected by region; toggle on the pricing page.
165
165
 
166
166
  All options are the second element of the reporter tuple.
167
167
 
168
+ <!-- AUTOGEN:options-table START — edit scripts/docs/options-meta.ts, then run npm run docs:gen -->
168
169
  | Option | Type | Default | Description |
169
170
  |---|---|---|---|
170
- | `template` | `'minimal' \| 'detailed' \| 'executive'` or array | `'minimal'` | Template(s) to generate. Pass an array to produce one PDF per template the template name is appended automatically (e.g. `report-detailed.pdf`). |
171
- | `outputFile` | `string` | `'playwright-report/{date}-report.pdf'` | Output path (supports tokens) |
172
- | `reportTitle` | `string` | `'Playwright Test Report'` | Title in header and cover |
173
- | `projectName` | `string` | from `package.json` | Project name shown in report |
174
- | `logo` | `string` | | Path to logo image (PNG / JPG / SVG) |
175
- | `primaryColor` | `string` | `'#CC785C'` | Brand colour (hex) |
176
- | `accentColor` | `string` | `'#3F7D58'` | Accent colour (hex) |
177
- | `watermark` | `string` | — | Diagonal watermark text (e.g. `'CONFIDENTIAL'`) |
178
- | `pdfPassword` | `string` | | Password-protect the PDF (requires `qpdf`) |
179
- | `licenseKey` | `string` | env `RF_LICENSE_KEY` | Subscription key (format `RFSU-…`) |
180
- | `compressionLevel` | `'auto' \| 'none' \| 'balanced' \| 'max'` | `'auto'` | Screenshot JPEG quality + inline failure cap |
181
- | `includeScreenshots` | `boolean` | `true` | Embed screenshots in the PDF. Set to `false` to omit images useful for exec-audience reports or reducing file size. |
182
- | `maxInlineFailures` | `number` | derived from `compressionLevel` | Cap on inline failures; overflow spills to `{basename}-failures.json` |
183
- | `maxFileSizeMb` | `number` | `8` | Soft cap; reporter re-renders with `max` compression once if exceeded |
184
- | `serverUrl` | `string` | `'https://reportforge.org'` | Licensing server base URL (override only for self-hosting) |
185
- | `open` | `boolean` | `false` | Open PDF after generation (local only) |
186
- | `shardResults` | `string \| string[]` | | Glob or path array of Playwright JSON shard files to merge into one PDF. |
187
- | `notify` | `object` | — | Notification channels: `slack`, `teams`, `discord` (each `{ url, enabled, on }`), `email` (`{ to, enabled, on, attachPdf }`). See [Notifications](#notifications). |
188
- | `historyFile` | `string` | `~/.reportforge/{key}/history.json` | Path to history JSON. Relative paths resolved from cwd at startup. |
189
- | `historySize` | `number` | `10` | Max run entries to keep (integer 2). |
190
- | `showTrend` | `boolean` | `true` | Set to `false` to disable history write and trend charts entirely. |
191
- | `flakinessTopN` | `number` | `5` | Max flaky tests to show in the `detailed` template flakiness table. `0` disables the table. |
192
- | `puppeteerExecutablePath` | `string` | auto-detect | Path to Chrome / Chromium |
171
+ | `outputFile` | `string` | `'playwright-report/{date}-report.pdf'` | Output path. Supports tokens: `{date}`, `{datetime}`, `{branch}`, `{status}`, `{total}`, `{passed}`, `{failed}`, `{project}`. Directory is created if absent. |
172
+ | `template` | `'minimal' \| 'detailed' \| 'executive'` or array | `'minimal'` | Template(s) to generate. Pass an array to produce one PDF per template in one run — the template name is appended to each output filename automatically (e.g. `report-detailed.pdf`). |
173
+ | `licenseKey` | `string` | env `RF_LICENSE_KEY` | Subscription key (format `RFSU-…`). Falls back to the `RF_LICENSE_KEY` environment variable. PDF generation is skipped when absent or invalid. |
174
+ | `logo` | `string` | | Path to a logo image (PNG, JPG, or SVG) to embed in the report header. Supports absolute and relative paths. |
175
+ | `primaryColor` | `string` | `'#CC785C'` | Primary brand colour (3-, 6-, or 8-digit hex). Used for headers and accent bars. |
176
+ | `accentColor` | `string` | `'#3F7D58'` | Accent brand colour (hex). Used for highlights and badges. |
177
+ | `watermark` | `string` | | Text to render as a diagonal watermark overlay on every page — e.g. `'CONFIDENTIAL'`, `'DRAFT'`. |
178
+ | `pdfPassword` | `string` | — | Password-protect the generated PDF. Requires `qpdf` installed on the system. |
179
+ | `reportTitle` | `string` | `'Playwright Test Report'` | Custom title for the report cover page and running header. |
180
+ | `projectName` | `string` | from `package.json` | Project or application name. Inferred from the `package.json` `name` field if absent. |
181
+ | `open` | `boolean` | `false` | Open the generated PDF automatically after generation. For local use only ignored in CI. |
182
+ | `puppeteerExecutablePath` | `string` | auto-detect | Full path to a Chrome or Chromium binary. Falls back to `PUPPETEER_EXECUTABLE_PATH` env, then system Chrome discovery. |
183
+ | `serverUrl` | `string` | `'https://reportforge.org'` | Base URL for the ReportForge licensing server. Override only for self-hosting or local development. |
184
+ | `compressionLevel` | `'auto' \| 'none' \| 'balanced' \| 'max'` | `'auto'` | Screenshot JPEG quality preset. `'auto'` picks based on failure volume; `'none'` keeps original PNGs; `'balanced'` uses JPEG q85; `'max'` uses JPEG q70. |
185
+ | `includeScreenshots` | `boolean` | `true` | Embed Playwright screenshots in the PDF. Set to `false` to omit images — useful for exec-audience reports or reducing file size. |
186
+ | `maxInlineFailures` | `number` | derived from `compressionLevel` | Cap on failure entries rendered inline in the PDF. Overflow is written to a sibling `{basename}-failures.json` sidecar file. |
187
+ | `maxFileSizeMb` | `number` | `8` | Soft cap on the final PDF size in MB. If exceeded, the report is re-rendered once with the `'max'` compression preset. |
188
+ | `shardResults` | `string \| string[]` | — | Glob or path array of Playwright JSON shard report files to merge into one PDF. See the Shard Merging docs. |
189
+ | `notify` | `object` | — | Notification channels: `slack`, `teams`, `discord` (each `{ url, enabled, on }`), `email` (`{ to, enabled, on, attachPdf }`). See the Notifications docs. |
190
+ | `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. |
191
+ | `historySize` | `number` | `10` | Maximum number of test runs to keep in the history file (integer 2). Older runs are pruned on append. |
192
+ | `showTrend` | `boolean` | `true` | Show the pass-rate sparkline and delta badge in the `detailed` template. Set to `false` to disable history tracking entirely. |
193
+ | `flakinessTopN` | `number` | `5` | Maximum flaky tests to show in the flakiness table (`detailed` template). Set to `0` to disable the table entirely. |
194
+ | `templatePath` | `string \| string[]` | — | 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. |
195
+ <!-- AUTOGEN:options-table END -->
193
196
 
194
197
  Full reference: [reportforge.org/docs#configuration](https://reportforge.org/docs#configuration).
195
198
 
package/dist/index.d.mts CHANGED
@@ -136,9 +136,12 @@ interface ReporterOptions {
136
136
  */
137
137
  shardResults?: string | string[];
138
138
  /**
139
- * Webhook notification channels. Post a pass/fail summary after each run.
139
+ * Notification channels. Post a pass/fail summary after each test run.
140
140
  * Each channel must have `enabled: true` to fire (default is `false`).
141
141
  * `on` controls the trigger: `'always'` (default), `'failure'`, or `'success'`.
142
+ *
143
+ * - `slack` / `teams` / `discord`: webhook URL channels
144
+ * - `email`: sends via Resend; `to` is required; `attachPdf: true` attaches the PDF
142
145
  */
143
146
  notify?: {
144
147
  slack?: {
@@ -156,6 +159,12 @@ interface ReporterOptions {
156
159
  on?: 'always' | 'failure' | 'success';
157
160
  enabled?: boolean;
158
161
  };
162
+ email?: {
163
+ to: string[];
164
+ on?: 'always' | 'failure' | 'success';
165
+ enabled?: boolean;
166
+ attachPdf?: boolean;
167
+ };
159
168
  };
160
169
  /**
161
170
  * Path to the history JSON file. Defaults to
package/dist/index.d.ts CHANGED
@@ -136,9 +136,12 @@ interface ReporterOptions {
136
136
  */
137
137
  shardResults?: string | string[];
138
138
  /**
139
- * Webhook notification channels. Post a pass/fail summary after each run.
139
+ * Notification channels. Post a pass/fail summary after each test run.
140
140
  * Each channel must have `enabled: true` to fire (default is `false`).
141
141
  * `on` controls the trigger: `'always'` (default), `'failure'`, or `'success'`.
142
+ *
143
+ * - `slack` / `teams` / `discord`: webhook URL channels
144
+ * - `email`: sends via Resend; `to` is required; `attachPdf: true` attaches the PDF
142
145
  */
143
146
  notify?: {
144
147
  slack?: {
@@ -156,6 +159,12 @@ interface ReporterOptions {
156
159
  on?: 'always' | 'failure' | 'success';
157
160
  enabled?: boolean;
158
161
  };
162
+ email?: {
163
+ to: string[];
164
+ on?: 'always' | 'failure' | 'success';
165
+ enabled?: boolean;
166
+ attachPdf?: boolean;
167
+ };
159
168
  };
160
169
  /**
161
170
  * Path to the history JSON file. Defaults to
package/dist/index.js CHANGED
@@ -11033,6 +11033,13 @@ var DataCollector = class {
11033
11033
  if (existing >= 0) this.failureRecords.splice(existing, 1);
11034
11034
  }
11035
11035
  }
11036
+ /**
11037
+ * Builds the final `ReportData` payload from all accumulated hook data.
11038
+ *
11039
+ * @param fullResult - Playwright's `FullResult` (contains `duration` + `status`).
11040
+ * @returns Structured data for the PDF generator, including projects tree,
11041
+ * aggregated stats, failures, environment info, and chart inputs.
11042
+ */
11036
11043
  finalize(fullResult) {
11037
11044
  const walker = new SuiteWalker();
11038
11045
  const projects = walker.build(this.rootSuite, this.resultMap);
@@ -11967,6 +11974,15 @@ var import_path6 = __toESM(require("path"));
11967
11974
  var import_fs9 = __toESM(require("fs"));
11968
11975
  var MAX_BRANCH_LENGTH = 50;
11969
11976
  var FilenameResolver = class {
11977
+ /**
11978
+ * Expands `{date}`, `{branch}`, and `{status}` tokens in `template`, then
11979
+ * resolves to an absolute path and creates the parent directory.
11980
+ *
11981
+ * @param template - Output path, possibly relative to `cwd` and possibly
11982
+ * containing `{date}`, `{branch}`, or `{status}` tokens.
11983
+ * @param ctx - Runtime values for token expansion.
11984
+ * @returns Absolute path with parent directories created.
11985
+ */
11970
11986
  resolve(template, ctx) {
11971
11987
  const date = this.formatDate(ctx.date);
11972
11988
  const branch = this.sanitiseBranch(ctx.branch);
@@ -11976,6 +11992,14 @@ var FilenameResolver = class {
11976
11992
  import_fs9.default.mkdirSync(import_path6.default.dirname(absolute), { recursive: true });
11977
11993
  return absolute;
11978
11994
  }
11995
+ /**
11996
+ * Inserts `suffix` before the file extension so multi-template runs produce
11997
+ * unique filenames from the same base path.
11998
+ *
11999
+ * @example
12000
+ * injectTemplateSuffix('/out/2026-report.pdf', 'executive')
12001
+ * // → '/out/2026-report-executive.pdf'
12002
+ */
11979
12003
  injectTemplateSuffix(outputPath, suffix) {
11980
12004
  const ext = import_path6.default.extname(outputPath);
11981
12005
  const base = outputPath.slice(0, outputPath.length - ext.length);
@@ -12098,6 +12122,24 @@ var PdfGenerator = class {
12098
12122
  } catch {
12099
12123
  }
12100
12124
  }
12125
+ /**
12126
+ * Generates one PDF per template source and returns their absolute output paths.
12127
+ *
12128
+ * Launches a single Puppeteer browser instance shared across all template
12129
+ * renders to avoid the 2–5 s startup cost per template. Each render pass goes
12130
+ * through: failure pagination → screenshot embedding → Handlebars render →
12131
+ * temp HTML write → `page.pdf()`.
12132
+ *
12133
+ * Size cap enforcement: if the first-pass PDF exceeds `options.maxFileSizeMb`,
12134
+ * compression settings are tightened (quality 55, maxWidth 800, inline cap
12135
+ * scaled to fit) and the PDF is re-rendered once. A second overrun warns but
12136
+ * is not re-rendered.
12137
+ *
12138
+ * @param data - Assembled `ReportData` (projects, stats, failures, charts).
12139
+ * @param options - Validated reporter options.
12140
+ * @param _licenseInfo - Kept for API symmetry; unused in this method.
12141
+ * @returns Absolute paths of written PDF files.
12142
+ */
12101
12143
  async generateAll(data, options, _licenseInfo) {
12102
12144
  const sources = this.resolveTemplateSources(options);
12103
12145
  const isMulti = sources.length > 1;
@@ -12628,7 +12670,7 @@ var PdfReporter = class {
12628
12670
  this.dataCollector = new DataCollector();
12629
12671
  this.pdfGenerator = new PdfGenerator();
12630
12672
  this.options = parseOptions(rawOptions);
12631
- const version = true ? "0.2.1" : "0.x";
12673
+ const version = true ? "0.2.2" : "0.x";
12632
12674
  logger.info(`@reportforge/playwright-pdf v${version} initialised`);
12633
12675
  this.licenseClient = new LicenseClient({
12634
12676
  licenseKey: this.options.licenseKey,
package/dist/index.mjs CHANGED
@@ -11034,6 +11034,13 @@ var DataCollector = class {
11034
11034
  if (existing >= 0) this.failureRecords.splice(existing, 1);
11035
11035
  }
11036
11036
  }
11037
+ /**
11038
+ * Builds the final `ReportData` payload from all accumulated hook data.
11039
+ *
11040
+ * @param fullResult - Playwright's `FullResult` (contains `duration` + `status`).
11041
+ * @returns Structured data for the PDF generator, including projects tree,
11042
+ * aggregated stats, failures, environment info, and chart inputs.
11043
+ */
11037
11044
  finalize(fullResult) {
11038
11045
  const walker = new SuiteWalker();
11039
11046
  const projects = walker.build(this.rootSuite, this.resultMap);
@@ -11968,6 +11975,15 @@ import path7 from "path";
11968
11975
  import fs8 from "fs";
11969
11976
  var MAX_BRANCH_LENGTH = 50;
11970
11977
  var FilenameResolver = class {
11978
+ /**
11979
+ * Expands `{date}`, `{branch}`, and `{status}` tokens in `template`, then
11980
+ * resolves to an absolute path and creates the parent directory.
11981
+ *
11982
+ * @param template - Output path, possibly relative to `cwd` and possibly
11983
+ * containing `{date}`, `{branch}`, or `{status}` tokens.
11984
+ * @param ctx - Runtime values for token expansion.
11985
+ * @returns Absolute path with parent directories created.
11986
+ */
11971
11987
  resolve(template, ctx) {
11972
11988
  const date = this.formatDate(ctx.date);
11973
11989
  const branch = this.sanitiseBranch(ctx.branch);
@@ -11977,6 +11993,14 @@ var FilenameResolver = class {
11977
11993
  fs8.mkdirSync(path7.dirname(absolute), { recursive: true });
11978
11994
  return absolute;
11979
11995
  }
11996
+ /**
11997
+ * Inserts `suffix` before the file extension so multi-template runs produce
11998
+ * unique filenames from the same base path.
11999
+ *
12000
+ * @example
12001
+ * injectTemplateSuffix('/out/2026-report.pdf', 'executive')
12002
+ * // → '/out/2026-report-executive.pdf'
12003
+ */
11980
12004
  injectTemplateSuffix(outputPath, suffix) {
11981
12005
  const ext = path7.extname(outputPath);
11982
12006
  const base = outputPath.slice(0, outputPath.length - ext.length);
@@ -12099,6 +12123,24 @@ var PdfGenerator = class {
12099
12123
  } catch {
12100
12124
  }
12101
12125
  }
12126
+ /**
12127
+ * Generates one PDF per template source and returns their absolute output paths.
12128
+ *
12129
+ * Launches a single Puppeteer browser instance shared across all template
12130
+ * renders to avoid the 2–5 s startup cost per template. Each render pass goes
12131
+ * through: failure pagination → screenshot embedding → Handlebars render →
12132
+ * temp HTML write → `page.pdf()`.
12133
+ *
12134
+ * Size cap enforcement: if the first-pass PDF exceeds `options.maxFileSizeMb`,
12135
+ * compression settings are tightened (quality 55, maxWidth 800, inline cap
12136
+ * scaled to fit) and the PDF is re-rendered once. A second overrun warns but
12137
+ * is not re-rendered.
12138
+ *
12139
+ * @param data - Assembled `ReportData` (projects, stats, failures, charts).
12140
+ * @param options - Validated reporter options.
12141
+ * @param _licenseInfo - Kept for API symmetry; unused in this method.
12142
+ * @returns Absolute paths of written PDF files.
12143
+ */
12102
12144
  async generateAll(data, options, _licenseInfo) {
12103
12145
  const sources = this.resolveTemplateSources(options);
12104
12146
  const isMulti = sources.length > 1;
@@ -12629,7 +12671,7 @@ var PdfReporter = class {
12629
12671
  this.dataCollector = new DataCollector();
12630
12672
  this.pdfGenerator = new PdfGenerator();
12631
12673
  this.options = parseOptions(rawOptions);
12632
- const version = true ? "0.2.1" : "0.x";
12674
+ const version = true ? "0.2.2" : "0.x";
12633
12675
  logger.info(`@reportforge/playwright-pdf v${version} initialised`);
12634
12676
  this.licenseClient = new LicenseClient({
12635
12677
  licenseKey: this.options.licenseKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reportforge/playwright-pdf",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
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",
@@ -60,7 +60,9 @@
60
60
  "typecheck": "tsc --noEmit",
61
61
  "prepublishOnly": "npm run typecheck && npm run test && npm run build",
62
62
  "generate-license": "tsx scripts/generate-license.ts",
63
- "snapshot-png": "tsx scripts/snapshot-png.ts"
63
+ "snapshot-png": "tsx scripts/snapshot-png.ts",
64
+ "docs:gen": "tsx scripts/docs/sync-docs.ts --write",
65
+ "check:docs": "tsx scripts/docs/sync-docs.ts --check"
64
66
  },
65
67
  "peerDependencies": {
66
68
  "@playwright/test": ">=1.40.0",