Merv-Local + Cucumber-js guide
Introduction
Cucumber-js
runs Gherkin scenarios in Node.js. Pair it with
Playwright
for browser automation and Merv-Local for rich HTML/JSON reports via the
merv-client/cucumber-formatter plugin.
Each scenario becomes one MERV test case; each Gherkin
step becomes a MERV step with pass/fail status. Scenario tags (e.g.
@smoke) are stored on the testcase for dashboard filters and KPI charts.
Java Cucumber? See the
Merv-Local + Cucumber (Java) guide for
MervCucumberHandler and Maven setup.
- How to install
merv-client,merv-client-cucumber, and Playwright - How to use automated setup (
doctor setup) or configure files manually - How to align
@playwright/testversions inpackage.json(TypeScript projects) - How to register
merv-client-cucumber(or legacymerv-client/cucumber-formatter) incucumber.js - How to bind the Playwright
pagefor step screenshots - How to add
info,testdata, andvalidationrows withMervReporter - Where live and final reports appear under
merv.report.folder - How to send the same runs to Merv-Server
Installing merv-client
From your BDD project root (where package.json and feature files live):
npm install -D merv-client merv-client-cucumber @cucumber/cucumber
# Optional — browser / UI action capture:
npm install -D merv-client-playwright @playwright/test
npx playwright install
Prefer merv-client-cucumber for the formatter. Legacy
merv-client/cucumber-formatter still works when the adapter package is installed.
Requires @cucumber/cucumber ≥ 7 and Node.js 18+.
Prefer merv-client 4.0.22+ so npm resolves peers cleanly;
otherwise use npm install --legacy-peer-deps.
Automated setup (doctor)
After install, run the Cucumber doctor. It creates or heals MERV wiring
without wiping unrelated cucumber.js options or your existing feature files.
# Install first (required on every machine)
npm install -D merv-client-cucumber
# Then run doctor
npx merv-client-cucumber doctor setup
npx merv-client-cucumber doctor setup --typescript
# Windows alternatives if npx bin is not found
npm exec -- merv-client-cucumber doctor setup
node node_modules/merv-client-cucumber/dist/cli.js doctor setup
- Fills missing
merv.*keys only - Adds
merv-client-cucumbertoformat(migrates legacy formatter path if present) - Adds require globs / npm scripts only when missing
- Scaffolds demo
features/only when no.featurefiles exist
Then run npx cucumber-js and open the dashboard with npx merv show-report.
Prefer manual setup below if you want every file edited by hand.
Manual setup
Skip doctor and configure MERV yourself: create
merv.properties,
register the formatter, then optionally
Playwright hooks and
custom steps.
package.json — align Playwright versions (important)
When your project uses merv-client (especially via a local
file:…/merv-client-js link), npm may install a second copy of
@playwright/test / playwright-core under
node_modules/merv-client/node_modules. TypeScript then treats them as different types.
In hooks you pass this.page into
MervPlaywright.setAutomationToolObject or
MervPlaywright.screenshot. If versions differ, the IDE and tsc report errors
such as:
Argument of type 'Page' is not assignable to parameter of type 'Page'.
Type 'Page' is missing the following properties from type 'Page':
ariaSnapshot, cancelPickLocator, …
Fix: pin one @playwright/test version in your project and use npm
overrides so merv-client resolves the same Playwright packages
as your app. Run npm install after editing package.json.
Recommended package.json snippet
{
"devDependencies": {
"@cucumber/cucumber": "^10.0.0",
"@playwright/test": "1.59.1",
"merv-client": "^4.0.22",
"tsx": "^4.19.0",
"typescript": "^5.8.0"
},
"overrides": {
"merv-client": {
"@playwright/test": "$@playwright/test",
"playwright": "$playwright",
"playwright-core": "$playwright-core"
}
}
}
-
Use an exact
@playwright/testversion (no^on the line you override from) — pick the latest stable release your project supports. -
The
$@playwright/testsyntax tells npm to force nested dependencies to use your project’s root Playwright version. -
Verify with:
npm ls @playwright/test playwright-core— every entry should show the same version (e.g.1.59.1). -
If you use
file:…/merv-client-js, keep overrides in the consumer project (your Cucumber repo), not only inside themerv-clientsource tree. -
Restart the TypeScript server after
npm install(TypeScript: Restart TS Server in VS Code / Cursor).
Cucumber 10 projects: if you see ERR_REQUIRE_ESM from
@cucumber/messages, you can also pin messages in overrides, for example
"@cucumber/messages": "24.1.0" alongside the Playwright block above.
Playwright-only projects (no Cucumber) need the same overrides when using a
file:-linked merv-client — see
Playwright guide — package.json overrides.
Configure merv.properties
Create merv.properties at the project root (same folder you run
npx cucumber-js from). The formatter resolves it from process.cwd()
or an ancestor directory.
Sample Configuration
merv.local=true
merv.regression_suite=Cucumber Regression
merv.report.folder=./merv-reports/
Download sample merv.properties
Common properties
| Property | Role |
|---|---|
merv.local |
true — Merv-Local: write HTML/JSON reports on disk under
merv.report.folder (no cloud API).false — Merv-Server: send suites, cases, and steps to the MERV
cloud API (set merv.server, API key, and hierarchy as well).
|
merv.report.folder |
Root for timestamped run folders and index.html. |
merv.regression_suite |
Suite title in JSON and HTML. |
merv.screenshot |
true — capture a viewport PNG per Gherkin step (requires Playwright hooks below). Failed steps always capture even when false.false — skip PNGs on passed steps only (smaller report folders).
|
merv.emailable.html |
true — write interactive emailable-report.html when the suite finishes
(doctor defaults to false). See
Share, Download & emailable.
|
merv.step.allowed |
Optional allowlist: info, hook, assertion, action.
Categories not listed are omitted from the report / server steps.
Example: merv.step.allowed=info,assertion,action.
|
merv.chai=true |
When the optional chai package is installed, record Chai
expect / assert as MERV ASSERTION steps
during an active scenario (default on with the Cucumber formatter).
Set merv.chai=false to disable. If you also use Playwright
expect in the same project, both appear in the report
(EXPECT + ASSERTION) — see
Playwright guide — Chai assertions.
|
merv.zip.export |
true — write merv-report-upload.zip for import into the MERV web UI.false — skip ZIP export at end of run.
|
Register the formatter
Cucumber auto-loads a file named cucumber.js (or cucumber.cjs /
cucumber.mjs) from the project root. Add the MERV formatter to the
format array — do not pass --format on the CLI unless
you intend to override the whole config (that disables MERV reporting).
// cucumber.js
module.exports = {
default: {
require: [
'features/support/**/*.js',
'features/step-definitions/**/*.js'
],
format: [
'progress-bar',
'merv-client/cucumber-formatter',
'json:reports/cucumber-report.json'
],
formatOptions: {
snippetInterface: 'async-await',
merv: {}
}
}
};
Load support files before step definitions so global Before hooks
(browser init) run before tagged hooks that set up page objects.
Run tests with:
npx cucumber-js
Or add an npm script: "test": "cucumber-js". Optional:
npx cucumber-js features/home.feature for one feature file.
Playwright hooks
The MERV formatter does not launch a browser. Your Cucumber World starts Playwright; MERV needs three hook calls so step screenshots and custom-step captures work.
Before—MervPlaywright.setAutomationToolObject(AutomationTool.PLAYWRIGHT, this.page)binds the active page.AfterStep—await MervPlaywright.screenshot({ testStepId, result })stashes step PNGs (respectsmerv.screenshot; failed steps always capture).After—MervPlaywright.clear()before you close the browser — releases the page binding and screenshot stash.
| Hook | MERV API | Required? |
|---|---|---|
Before |
MervPlaywright.setAutomationToolObject(…) |
Yes — for step screenshots and validation(…, true) PNGs |
AfterStep |
MervPlaywright.screenshot(…) |
Yes — when merv.screenshot=true or you want failed-step PNGs |
After |
MervPlaywright.clear() |
Yes — call before closeBrowser() |
Before / After |
initBrowser / closeBrowser |
Your project — not MERV (wrap chromium.launch() on the World) |
MERV calls only
const { AutomationTool, MervPlaywright } = require('merv-client');
// 1 — Before: bind page
MervPlaywright.setAutomationToolObject(AutomationTool.PLAYWRIGHT, this.page);
// 2 — AfterStep: stash step screenshot
await MervPlaywright.screenshot({ testStepId, result });
// 3 — After: clear MERV state (before closing the browser)
MervPlaywright.clear();
Full hooks.js example
// features/support/hooks.js
const { Before, After, AfterStep } = require('@cucumber/cucumber');
const { AutomationTool, MervPlaywright } = require('merv-client');
Before(async function () {
await this.initBrowser(process.env.BROWSER || 'chromium'); // your World
MervPlaywright.setAutomationToolObject(AutomationTool.PLAYWRIGHT, this.page);
});
AfterStep(async function ({ testStepId, result }) {
await MervPlaywright.screenshot({ testStepId, result });
});
After(async function () {
MervPlaywright.clear();
await this.closeBrowser(); // your World
});
Set merv.screenshot=true in merv.properties to capture PNGs on
passed Gherkin steps. Failed steps are always captured even when
merv.screenshot=false.
Custom steps (MervReporter)
Gherkin steps map to MERV automatically via the formatter. For extra report rows inside a step
definition — expected/actual checks, request payloads, prerequisite notes — call
MervReporter from merv-client (same API as Java Cucumber, TestNG, and JUnit 5).
MervReporter only works while a scenario is running and
merv-client/cucumber-formatter is registered in cucumber.js.
// features/step-definitions/home-steps.js
const { Then } = require('@cucumber/cucumber');
const { MervReporter } = require('merv-client');
Then('the welcome message is shown', async function () {
const text = await this.page.textContent('h1');
await MervReporter.validation('Welcome heading', 'Welcome', text ?? '');
await MervReporter.info(`Checked at ${new Date().toISOString()}`);
});
Then('I log the cart payload', async function () {
const payload = JSON.stringify({ sku: 'SKU-1', qty: 2 });
await MervReporter.testdata('Cart request', payload);
});
Each call appends a typed row to the current scenario in live and final HTML reports.
| Method | Step type | Role |
|---|---|---|
MervReporter.info(text) |
PREREQUISITE | Info / prerequisite note. |
MervReporter.testdata(name, string) |
TEST_DATA | Inline string or JSON payload. |
MervReporter.testdataFile(name, path) |
TEST_DATA | File attachment (see below). |
MervReporter.validation(name, expected, actual, screenshot?) |
ASSERTION | Expected vs actual; fails the Cucumber step when values differ. |
MervReporter.addCustomStep(name, status?, errorMessage?) |
CUSTOM | Arbitrary row with pass/fail/skipped status. |
MervReporter.addStep(name, type, …) |
varies | Low-level: testdata, assertion, or information. |
Failed validation calls throw and fail the Gherkin step unless
merv.plugin_assertion_soft=true in merv.properties (row is still recorded as failed).
File test data
testdataFile copies the file into {runFolder}/attachments/ and shows a download bar
in the report (large files are not inlined as raw text):
const path = require('node:path');
const { MervReporter } = require('merv-client');
await MervReporter.testdataFile('API payload', path.join('testdata', 'order.json'));
await MervReporter.testdataFile('Expected UI', path.join('testdata', 'expected.png'));
- Text / JSON / CSV — preview in the step when small enough
- Images — inline thumbnail in the report
- Other files — download bar (max 20 MB per file)
Screenshots on custom steps
info, testdata, and testdataFile do not capture a
viewport PNG automatically. To attach a screenshot to a validation row, pass true as the last
argument:
await MervReporter.validation('Page title', 'Home', title, true);
Gherkin step screenshots (after each Cucumber step) are separate — controlled by
merv.screenshot=true and the MervPlaywright.screenshot hook above.
Running your suite
npx cucumber-js
While tests run, MERV writes json/merv-report.json with
"running": true and refreshes merv-index-data.json so the dashboard can
poll live counts. When Cucumber exits, the suite is marked complete and
merv-report-upload.zip is created when merv.zip.export=true.
Viewing Merv reports
Reports live under {merv.report.folder} (for example ./merv-reports/).
Open them through a local web server — not via file://.
Live dashboard
- Start
npx cucumber-js(or your npmtestscript). - Open the dashboard with
npx merv show-report(preferred) or Live Server onmerv-reports/index.html. - Within ~5 seconds a new suite card appears with In progress.
- Click View Cases →
merv-report-live.htmlfor step-by-step live updates (~2s poll).
Keep index.html open during the run; it patches suite cards and KPI charts from
merv-index-data.json without a full page reload.
Open with a web server
merv.properties lives):
npx merv show-report
npx merv-client show-report
npm run show-report
# Explicit folder / options
npx merv show-report ./merv-reports
npx merv show-report --port 6174
npx merv show-report --host 127.0.0.1
npx merv show-report --host 0.0.0.0
npx merv show-report --no-open
npx merv show-report ./merv-reports --port 8080 --no-open
Opens http://127.0.0.1:6174/ (dashboard). Also available:
http://127.0.0.1:6174/merv-logs.html (Merv-Logs). Stop with Ctrl+C.
- Install the Live Server extension.
- Right-click
merv-reports/index.htmland choose Open with Live Server. - While tests run, open
{runFolder}/html/merv-report-live.htmlon the same server.
npx merv show-report). Use npx merv show-report and open
http://127.0.0.1:6174/merv-logs.html (or the Merv-Logs sidebar link — opens in a new tab).
See the Merv-Logs guide.
Use the Timezone control and Show detailed metadata checkbox to format timestamps and show suite / scenario names on each line.
- After a run, check disk:
merv-reports/log/*.ndjsonandmerv-reports/log/manifest.json(path followsmerv.report.folder). - Use merv-client and merv-client-cucumber at 4.0.22+ (and merv-client-playwright when using Playwright).
- Cucumber:
cucumber.jsmust include themerv-client-cucumberformatter (runnpx merv-client-cucumber doctor setupto heal). - For Playwright action rows with locators in Merv-Logs, set
merv.playwright.actions=trueand wrap the page withenableMervPlaywrightPagein your hooks (doctor adds the property key). - Do not set
merv.logger.file=falseunless you intentionally disable file logs. - View logs with
npx merv show-report— opening HTML alone does not load the live log stream.
- Right-click
merv-reports/index.htmland choose Open in Browser. - Open suite reports from
{runFolder}/html/the same way. - Confirm the address bar shows
http://localhost:…, notfile://.
Other editors and CI
Any local static server works: npx serve merv-reports or
python3 -m http.server --directory merv-reports, then open
http://localhost:…/index.html.
Merv-Server mode
To stream results to https://merv.online instead of local folders,
set merv.local=false and add your API key and hierarchy UUID. Full walkthrough:
Merv-Server user guide.
merv.local=false
merv.server=https://merv.online/api/v1
merv.api_key=your-api-key
merv.parent_hierarchy=your-hierarchy-uuid
merv.regression_suite=Cucumber Regression
merv.screenshot=true
The same cucumber.js formatter and Playwright hooks apply; no Playwright reporter is required.
Troubleshooting
| Issue | What to check |
|---|---|
| No MERV report after run | Use npx cucumber-js without extra --format flags. Ensure cucumber.js lists merv-client/cucumber-formatter. |
| Dashboard empty until run finishes | Open index.html via http://localhost. Upgrade merv-client to 4.0.22+ for live index updates during Cucumber runs. |
Steps show as Step abc123 |
Upgrade merv-client (Cucumber ≥ 7). Ensure duplicate step definitions are removed. |
| No step screenshots | Set merv.screenshot=true. Add all three MERV hook calls (see Playwright hooks): bind page in Before, MervPlaywright.screenshot in AfterStep, MervPlaywright.clear() in After. |
Page type mismatch in hooks / MervPlaywright |
Duplicate @playwright/test versions — add package.json overrides (see Playwright overrides); run npm install; npm ls playwright-core should show one version. |
Multiple step definitions match |
Keep one shared step per pattern in common-steps.js; use World handlers for page-specific logic. |
Custom MervReporter steps missing |
Register merv-client/cucumber-formatter in cucumber.js. Call MervReporter only inside step definitions during a running scenario (not in BeforeAll). |
What’s next
- Share, Download & emailable — LAN share, offline zip,
merv.emailable.html - Cucumber (Java) guide — Maven
MervCucumberHandler - Playwright Test guide —
@playwright/testreporter (non-BDD) - Merv documentation — dashboard tour, JSON contract
- Merv-Server user guide
- Forum / defects
MERV