@qualflare/cucumberjs
v0.7.2
Published
Native CucumberJS formatter for Qualflare — captures Gherkin step traces, Scenario Outline rows, per-attempt retry history, screenshots and metadata.
Maintainers
Readme
@qualflare/cucumberjs
A native CucumberJS reporter for Qualflare — captures test results directly
from your cucumber-js run: Feature/Scenario status, per-attempt retry history, screenshots, videos,
Given/When/Then step traces, Scenario Outline rows, and author-facing metadata (labels, links, tags,
custom attachments).
The formatter itself makes no network calls. It writes a report directory, and
qualflare-cli uploads it — which is what lets any
number of sharded CI jobs merge into a single Launch.
Install
npm install --save-dev @qualflare/cucumberjsRequires @cucumber/cucumber >=10.8.0 (installed separately as a peer dependency) and Node
>=18. You also need qualflare-cli v0.1.16 or
newer to upload what this formatter writes.
The peer range is deliberately open-ended rather than capped at a known-good major, so a new
cucumber-js release never hard-blocks npm install for you. Every major from 10.8 through 13 is
exercised in CI against a real cucumber-js run; newer majors are untested but not refused —
please open an issue if one
misbehaves.
Quickstart
// cucumber.json
{
"default": {
"format": ["@qualflare/cucumberjs/formatter"],
"formatOptions": {
"environment": "staging"
}
}
}Then run your tests and upload the results — two steps, no token needed for the first:
# 1. Run. Writes ./qualflare-results (JSON + any videos). Zero network calls.
npx cucumber-js
# 2. Upload. `qf login <identifier> <token>` stores the credential once.
qf <your-project-identifier> collect ./qualflare-resultsRequires
@qualflare/cliv0.1.24 or newer. Screenshots are written intooutputDirand referenced by name (localImagePath) instead of being base64-inlined into the report, the same way videos already were — including the ones you hand toWorld.attach(), which have no file on disk and are written out for you. An older CLI does not read the field, and because such an attachment carries neither content nor a storage key the server records it from its name alone — an undownloadable placeholder. Upgrade the CLI before upgrading this formatter.Videos are opt-in; screenshots are not.
collectuploads the report and the screenshots always, but a video only when asked:--upload-artifacts=video(orQF_UPLOAD_ARTIFACTS=video). Named kinds are added to that default, so asking for video does not turn screenshots off;--upload-artifacts=nonedeclines everything, screenshots included. Nothing is dropped silently —collectprints how many it skipped and the exact flag to include them.
That's it — Feature/Scenario results, retries, and any screenshots you already attach arrive as one
Launch. See examples/basic/ for a complete runnable project.
Sharded CI
Point every shard at the same outputDir and collect once at the end. Each process writes its
own uniquely-named file, so shards never overwrite each other, and qf collect merges every file
in the directory into a single Launch:
# in each parallel job — note they all write to the same directory
npx cucumber-js --shard "$SHARD_INDEX/$SHARD_TOTAL"
# once, after all shards finish (e.g. with the directory restored from CI artifacts)
qf <your-project-identifier> collect ./qualflare-resultsNo --shard flag is needed on the CLI side: merging is driven purely by which files are in the
directory.
Enriching your tests
import { Given, When } from '@cucumber/cucumber';
import { qualflare } from '@qualflare/cucumberjs';
Given('a user with valid credentials', function () {
qualflare.label('epic', 'Authentication');
qualflare.tag('smoke');
});
When('they log in', async function () {
await qualflare.step('fill in credentials', async () => {
await this.page.fill('#email', '[email protected]');
await this.page.fill('#password', 'correct-horse-battery-staple');
});
await qualflare.step('submit and verify redirect', async () => {
await this.page.click('#submit');
await this.page.waitForURL('**/dashboard');
});
});See docs/METADATA-API.md for the full reference (labels, links, tags,
description, priority, parameters, custom attachments, nested steps).
Configuration
Every option can be set either as a formatOptions entry or via a QUALFLARE_* environment
variable. Full table, precedence rules, and auto-detection behavior (git branch/commit, CI
provider/build/PR) in docs/CONFIGURATION.md.
One option is worth calling out because it fails late: environment is matched against the
environment's uid (slug), not its display name, so Staging in the UI is staging here. A
wrong value cannot fail at run time — this package makes no network calls — so the run succeeds and
collect 404s afterwards. See
the note in the configuration docs.
Test reports
This formatter is tested with itself. e2e/ is a cucumber-js suite covering this package's own
behaviour — the metadata API, nested steps, image attachments and per-attempt retry history — run by
this formatter and uploaded to Qualflare on every merge to main. The results below are that suite's,
reported through the code this README documents:
Every case there is meant to pass, so a red run is a real regression rather than a fixture that fails
on purpose. Deliberately-failing cases live in test/integration/, which is never uploaded.
Known limitations
BeforeAll/AfterAllattachments need the hook to fail — a failed global hook becomes a synthetic Case and its attachments land there; a passing one produces no Case, so they are dropped.- Retries carry per-attempt errors, but everything else is the final attempt —
Case.attemptsrecords each attempt's status, duration and error; steps, labels, links, tags, priority, properties and attachments come from the last attempt only, so an abandoned attempt's step trace is discarded rather than replayed alongside the final one.
Full details in docs/LIMITATIONS.md.
Development
npm run typecheck # tsc --noEmit
npm run lint # eslint .
npm run build # tsup — dual ESM+CJS, .d.ts
npm test # unit tests (vitest)
npm run test:integration # spawns a real cucumber-js run against a fixture project + mock serverRelease process: see RELEASING.md.
License
Apache-2.0
