Getting started
Cypress
The same PDF reports for Cypress runs. Your test's real command trail becomes the report's Steps to Reproduce, so a failure arrives with the actions that caused it. Your subscription issues a key for each test runner, so Cypress gets its own key and its own allowance of machines, separate from the ones your other suites use.
Install
npm install -D @reportforge/cypress-pdfThe package bundles its own report engine and uses the Node runtime Cypress already runs your plugins in, so there is nothing else to install.
Quick start
Register the plugin inside setupNodeEvents:
import { defineConfig } from 'cypress';import { registerReportForgePdf } from '@reportforge/cypress-pdf';export default defineConfig({ e2e: { setupNodeEvents(on, config) { registerReportForgePdf(on, config, { template: 'detailed', outputFile: 'reports/{date}-report.pdf', }); return config; }, },});export RF_LICENSE_KEY=RFCY-XXXX-XXXX-XXXX-XXXXnpx cypress runYour tests always run in full. Without an active subscription only the PDF is skipped, and the run summary says so. Nothing is generated during cypress open, so an interactive debugging session never triggers a report.
Command trail and live runs
Cypress records its command log in the browser, and that log is gone by the time a run finishes. One import in your support file hands it to the reporter as each test ends:
import '@reportforge/cypress-pdf/support';Then turn on whichever of the two features you want:
registerReportForgePdf(on, config, { capture: { steps: true }, // Steps to Reproduce in the PDF live: { enabled: true }, // shareable watch page during the run});The import is optional and safe to leave out. Without it the report still generates, just without the trail and without live streaming, and nothing errors. With live.enabled the run prints a shareable watch link at the start; each test appears as it begins and its full command trail attaches the moment it finishes.
Configuration
Options are the third argument to registerReportForgePdf, using the same camelCase names as the Node.js reporter, so the full options reference applies as-is:
registerReportForgePdf(on, config, { template: 'detailed', outputFile: 'reports/{date}-{branch}-report.pdf', projectName: 'Checkout suite', capture: { steps: true, evidence: true }, evidenceUrlTemplate: 'https://ci.example.com/job/{buildId}/artifacts/{path}',});Options are validated by the engine, and a bad key is reported with the exact path that is wrong. Failure screenshots are embedded in the report automatically. The spec video feeds the defect log's evidence links; pair it with evidenceUrlTemplate for clickable CI links.
How it works
- The support file buffers each test's command log in the browser and sends it to the plugin as the test ends.
- The plugin collects Cypress's own run results when the run finishes and merges in the captured trails.
- The bundled engine validates your license, renders the PDF with Chrome, and prints the output path in the run output.
Retried tests render as flaky with their full attempt history. Overrides for unusual environments: RF_NODE_PATH (Node binary), PUPPETEER_EXECUTABLE_PATH (browser), RF_ENGINE_PATH (engine bundle).
Step 2 writes to a .reportforge/ directory in your project, including your resolved options. Add it to your .gitignore. If you set licenseKey or pdfPassword in your config rather than reading them from the environment, those values land in a file inside your repository. Prefer RF_LICENSE_KEY in the environment.
What lands in the trail
Step titles come from Cypress's own command log, which records the arguments you pass. Because that log reaches both the PDF and, with live enabled, a watch page that anyone holding the link can open, the reporter keeps values out of it by default.
Commands whose message is a selector or a description keep it, so you see GET #submit and VISIT /checkout. Everything else is recorded by name only. That includes value-bearing built-ins like type and setCookie, and it includes your own custom commands: cy.login(user, password) appears as LOGIN, never with the arguments. Cypress's own { log: false } option keeps a command out of the trail entirely, and redact masks patterns across the whole report if your tests surface secrets some other way.
Current limitations
- Trail entries show no individual timings. Cypress reports one duration per test rather than one per command.
- The trail is a flat list. Cypress has no grouping primitive equivalent to Playwright's test.step(), so there is no nesting to render.
- A cypress run drives one browser, so the cross-browser comparison section stays hidden. Run each browser separately and merge the results to get it.
- Skipped tests contribute no trail, since their hooks never run.