@watershed-labs/reporter
v0.1.0
Published
Unified reporting layer (HTML, JSON, JUnit, CI annotations)
Readme
@watershed-labs/reporter
Unified reporting layer for the Watershed ecosystem: console, HTML, JSON, JUnit XML, and CI annotations.
Part of the Watershed testing ecosystem.
Overview
@watershed-labs/reporter provides a consistent report shape across every Watershed template.
One formatter registration, one report format, one CI check — regardless of whether the
template is running web E2E, API, performance, or security tests.
Output formats
| Format | Status | Description | | ------------------------- | --------- | ------------------------------------------------------------------------------ | | Console (PinitoFormatter) | ✅ Active | Structured, coloured terminal output during the run | | OTel NDJSON | ✅ Active | Per-scenario log files for Datadog, Loki, Honeycomb, Jaeger | | HTML | ✅ Active | Self-contained single-file report, Pinito-aware rendering | | JSON | ✅ Active | Structured JSON to stdout or file — foundation for JUnit and CI | | JUnit XML | ✅ Active | CI-native test result format for GitHub Actions, Jenkins, Azure DevOps | | CI annotations | ✅ Active | GitHub Actions / GitLab CI inline annotations — auto-detected from environment |
Installation
npm install @watershed-labs/reporterUsage
// cucumber.js
import { defineConfig } from '@watershed-labs/config';
export default defineConfig(import.meta.url);defineConfig registers all active formatters automatically based on the current
environment. No manual wiring required in individual templates.
To override output paths or add additional formats:
export default defineConfig(import.meta.url, {
format: [
'@watershed-labs/reporter',
'html:./reports/report.html',
'json:./reports/results.json',
'junit:./reports/junit.xml'
]
});Format tokens
| Token | Output |
| --------------------- | ----------------------------------------------------------------------- |
| @watershed-labs/reporter | PinitoFormatter — console + OTel NDJSON |
| html:<path> | WatershedHtmlReporter — self-contained HTML report |
| json:<path> | Structured JSON — stdout or file |
| junit:<path> | JUnit XML at the specified path — for CI ingestion |
| ci | GitHub Actions / GitLab CI annotations — auto-detected from environment |
PinitoFormatter
Console formatter with OTel telemetry bridge. Active in all templates.
Configuration (formatOptions.pinito)
| Option | Default | Description |
| ------------------------ | ------------ | --------------------------------------------------------- |
| showProgress | false | Show (n/total) counter next to scenario name |
| showMetadataHeader | 'debug' | Show env/browser header: 'always', 'never', 'debug' |
| showFeatureDescription | true | Print feature description block |
| showStepLocation | true | Show # file:line next to each step |
| showDuration | true | Show step and scenario durations |
| showHooks | false | Show hook lines: 'always', 'never', 'failed' |
| showDebugOnFail | true | Print debug logs for failing scenarios |
| theme | 'cucumber' | Console colour theme |
Logging configuration (formatOptions.pinito.logging)
| Option | Default | Description |
| ----------------- | ------------------ | -------------------------------------------- |
| file | true | Write OTel NDJSON files to outputLogDir |
| filePerScenario | true | One file per scenario vs one file per worker |
| outputLogDir | './reports/logs' | Directory for NDJSON files |
| logLevel | 'info' | Minimum log level |
| perStep | true | Attach logs to each step in the HTML report |
| buffered | false | Buffer all logs and flush once per scenario |
| serviceName | 'watershed' | service.name in every OTel record |
WatershedHtmlReporter
Self-contained single-file HTML report generated after the run. Understands the Pinito schema natively — renders structured log output, step timing, and hook context rather than raw JSON blobs.
Key differences from @cucumber/html-formatter:
- Internal media types (
application/x.pinito.log,application/x.pinito.meta) filtered from display — they are telemetry, not report content - Structured log output rendered from the Pinito schema
- Hook lines labelled Before/After with source location
- AVIF screenshot thumbnails inline — produced by
@watershed-labs/screenshotvia sharp, typically 40–60KB each, safe to inline at any run scale - NDJSON file link per scenario when
logging.fileis enabled (local runs only) - Dark mode support
JSON output
Structured JSON representation of the full test run. Written to stdout or a file. Serves as the intermediate format consumed by JUnit XML and CI annotation generation. Also suitable for custom dashboards, trend analysis, and downstream tooling across all templates — web E2E, API, performance, and security.
# stdout
node cli.js --format json
# file
node cli.js --format json:./reports/results.jsonJUnit XML
Standard JUnit XML output for CI ingestion. Supported natively by GitHub Actions, Jenkins, CircleCI, Azure DevOps, and GitLab CI for PR-level test result reporting, failure summaries, and flaky test detection.
node cli.js --format junit:./reports/junit.xmlRelevant for all templates — not just web E2E. Performance (create-beaver) test regressions, security (create-pike) scan failures, and API (create-dipper) contract violations all benefit from JUnit XML for native CI result ingestion.
CI annotations
Inline failure annotations for GitHub Actions (::error) and GitLab CI
(gl-test-report). Auto-detected from environment variables — no configuration
required. Surfaces failures directly on the PR diff without opening a report file.
# auto-detected when CI=true and GITHUB_ACTIONS=true or GITLAB_CI=true
node cli.js --format ciParallel mode
In parallel runs, each worker writes to a worker-scoped output path.
The merge step runs automatically in AfterAll when @watershed-labs/hooks is registered.
// cucumber.js — parallel configuration
const workerId = process.env.CUCUMBER_WORKER_ID ?? '0';
export default defineConfig(import.meta.url, {
format: [`@watershed-labs/reporter`, `html:./reports/worker-${workerId}.html`, `json:./reports/worker-${workerId}.json`]
});Writing multiple workers to a single output file simultaneously will corrupt it.
The coordinator process merges worker files into the final report in AfterAll.
OTel NDJSON log files
Each scenario produces a .ndjson file in reports/logs/ when logging.file is
enabled. Every record follows the OpenTelemetry log data model and can be ingested
directly into Datadog, Grafana Loki, Honeycomb, or any OTel-compatible backend.
Records include a Trace block with traceId (per scenario) and spanId (per step),
enabling waterfall visualisation in Jaeger or Grafana Tempo.
In CI (process.env.CI set), the Trace block is stripped from passing scenarios
to reduce ingestion cost. Failing scenarios always include full trace data.
x-trace-id header
The traceId is injected as an x-trace-id HTTP header on every browser request via
CDP. If your application reads and forwards this header, failures can be correlated
across the full request chain in your tracing backend.
See the Watershed x-trace-id contract for details.
Licence
MIT — part of the Watershed ecosystem.
