Cucumber
Set up Cucumber for BDD testing and integrate test results with TestKase.
Overview
Cucumber is a BDD (Behavior-Driven Development) framework that lets you write tests in Gherkin syntax using natural language constructs — Given, When, Then. It bridges the gap between business stakeholders and developers by making test scenarios readable by everyone. Cucumber supports JavaScript, Java, Ruby, and other languages.
To integrate Cucumber results with TestKase, generate JSON output and report with --format cucumber.
Prerequisites
- Node.js 18+ (for JavaScript) or Java 11+ (for Java)
- A project to test
Installation
JavaScript
Install Cucumber as a dev dependency:
npm install --save-dev @cucumber/cucumberJava (Maven)
Add Cucumber dependencies to your pom.xml:
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.15.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>7.15.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>Project Setup
JavaScript
Create a cucumber.js configuration file in your project root:
// cucumber.js
module.exports = {
default: {
paths: ['features/**/*.feature'],
require: ['features/step_definitions/**/*.js'],
format: [
'progress-bar',
'json:test-results/cucumber.json',
],
publishQuiet: true,
},
};JavaScript Directory Structure
my-project/
cucumber.js
package.json
features/
login.feature
dashboard.feature
step_definitions/
login_steps.js
dashboard_steps.js
support/
world.js
test-results/ # Generated after running tests
cucumber.jsonJava
Create a runner class and configure the feature/step paths. Place feature files under src/test/resources/features/
and step definitions under src/test/java/:
my-project/
pom.xml
src/
test/
java/com/example/
steps/
LoginSteps.java
RunCucumberTest.java
resources/
features/
login.feature
cucumber.propertiesCreate the cucumber.properties file:
# src/test/resources/cucumber.properties
cucumber.plugin=pretty, json:test-results/cucumber.json
cucumber.glue=com.example.stepsWriting Tests
Feature File
Create a .feature file with Gherkin syntax (e.g., features/login.feature):
# features/login.feature
Feature: Login
Users should be able to log in with valid credentials
and see appropriate error messages for invalid attempts.
Scenario: [48271] User logs in with valid credentials
Given the user is on the login page
When the user enters "user@example.com" and "password123"
And the user clicks the login button
Then the user should be redirected to the dashboard
Scenario: [48272] User sees error for invalid password
Given the user is on the login page
When the user enters "user@example.com" and "wrong"
And the user clicks the login button
Then the user should see the error "Invalid credentials"
Scenario Outline: [48273] User logs in with multiple accounts
Given the user is on the login page
When the user enters "<email>" and "<password>"
And the user clicks the login button
Then the login result should be "<result>"
Examples:
| email | password | result |
| user@example.com | password123 | success |
| admin@example.com | admin456 | success |
| bad@example.com | wrong | failure |Step Definitions (JavaScript)
Create step definitions that match the Gherkin steps (e.g., features/step_definitions/login_steps.js):
// features/step_definitions/login_steps.js
const { Given, When, Then } = require('@cucumber/cucumber');
const assert = require('assert');
Given('the user is on the login page', async function () {
await this.page.goto('/login');
});
When('the user enters {string} and {string}', async function (email, password) {
await this.page.fill('[data-testid="email"]', email);
await this.page.fill('[data-testid="password"]', password);
});
When('the user clicks the login button', async function () {
await this.page.click('[data-testid="login-button"]');
});
Then('the user should be redirected to the dashboard', async function () {
assert.ok(this.page.url().includes('/dashboard'));
});
Then('the user should see the error {string}', async function (message) {
const error = await this.page.textContent('.error-message');
assert.strictEqual(error, message);
});
Then('the login result should be {string}', async function (result) {
if (result === 'success') {
assert.ok(this.page.url().includes('/dashboard'));
} else {
const error = await this.page.locator('.error-message');
assert.ok(await error.isVisible());
}
});Each Scenario name includes a 5-digit Automation ID in square brackets. The @testkase/reporter CLI
extracts these IDs using the regex \[(\d{5})\]. For the example above:
48271→ linked to the "valid login" test case in TestKase48272→ linked to the "invalid password" test case in TestKase48273→ linked to the "multiple accounts" test case in TestKase
Generate Automation IDs in TestKase first, then embed them in your Scenario names. The [XXXXX] pattern
can appear anywhere in the Scenario name — the reporter extracts all 5-digit IDs found in brackets.
Running Tests
JavaScript
Run Cucumber with JSON output:
npx cucumber-jsIf the format option is configured in cucumber.js, the JSON file is generated automatically.
To override on the command line:
npx cucumber-js --format json:test-results/cucumber.jsonJava
Run with Maven:
mvn testThe JSON plugin configured in cucumber.properties generates the output file automatically.
TestKase Integration
After generating the Cucumber JSON file, report results to TestKase:
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format cucumber \
--results-file test-results/cucumber.json--cycle-id is optional. If not provided, results are reported to TCYCLE-1 — the master test cycle for the project.
Automation ID Mapping
The reporter extracts 5-digit Automation IDs from Cucumber Scenario names using the [XXXXX] bracket pattern:
| Test Pattern | Scenario Name | Extracted ID |
|---|---|---|
| Standard Scenario | [48271] User logs in with valid credentials | 48271 |
| Another Scenario | [48272] User sees error for invalid password | 48272 |
| Scenario Outline | [48273] User logs in with multiple accounts | 48273 |
For Scenario Outline tests, all Example rows share the same [XXXXX] Automation ID.
The TestKase reporter aggregates results from all Example rows into a single test result.
The [XXXXX] pattern can appear anywhere in the Scenario name. Generate the 5-digit ID in TestKase
first, then embed it in your feature file.
Complete Example
1. Feature File
# features/login.feature
Feature: Login
Scenario: [48271] User logs in with valid credentials
Given the user is on the login page
When the user enters "user@example.com" and "password123"
And the user clicks the login button
Then the user should be redirected to the dashboard
Scenario: [48272] User sees error for invalid password
Given the user is on the login page
When the user enters "user@example.com" and "wrong"
And the user clicks the login button
Then the user should see the error "Invalid credentials"2. Run Tests and Generate JSON
npx cucumber-js --format json:test-results/cucumber.json3. Report Results to TestKase
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format cucumber \
--results-file test-results/cucumber.jsonTroubleshooting
JSON output file is empty
If the cucumber.json file is empty or contains [], verify the format option syntax in your
configuration:
// cucumber.js — correct format syntax
module.exports = {
default: {
format: ['json:test-results/cucumber.json'],
},
};Common mistakes:
- Missing the colon between format name and file path (
json:pathnotjson path) - Using
--format jsonwithout specifying the output file (JSON is printed to stdout) - The
test-results/directory does not exist — create it first withmkdir -p test-results
Step definitions not found
If Cucumber reports ? undefined steps, the step definition files are not being loaded. Check:
- The
requirepaths incucumber.jsmatch where your step files are located:
// cucumber.js
module.exports = {
default: {
require: ['features/step_definitions/**/*.js'],
},
};- For TypeScript step definitions, use
requireModuleto register the transpiler:
module.exports = {
default: {
require: ['features/step_definitions/**/*.ts'],
requireModule: ['ts-node/register'],
},
};- For Java, ensure the
glueproperty points to the correct package incucumber.properties.
Undefined steps — implement all step definitions
If you see Undefined. Implement with the following snippet: in the output, Cucumber found steps in
your feature files that do not have matching step definitions. This is not a configuration error —
you need to implement the missing steps.
Cucumber provides suggested code snippets in the output. Copy them into your step definition files and fill in the implementation:
# Run with --dry-run to see all undefined steps without executing tests
npx cucumber-js --dry-runReview the output and create step definitions for every Given/When/Then step used in your feature files.