Configures Cucumber for BDD scenarios - Cucumber-JVM (Java/Kotlin via JUnit 5), Cucumber-JS (Node), Cucumber-Ruby. Authors `.feature` files in Gherkin, writes step definitions in the host language, runs via the framework's runner, integrates with JUnit XML reporting. Use when the user mentions Cucumber, Gherkin, `.feature` files, or behavior-driven (BDD) tests in Java, Kotlin, JavaScript, or Ruby, as the canonical wrapper for any of the three official implementations.
90
89%
Does it follow best practices?
Impact
91%
1.03xAverage score across 10 eval scenarios
Passed
No findings from the security scan
Ops upload supplier price files every Monday. features/price-import.feature
covers exactly one case: a file with a single valid row. Everything that actually
goes wrong on a Monday - a file where some rows are fine and some are not, and a
file whose header columns are named wrong - has no scenario at all.
The support team reads this feature file and is the group that tells us what a rejection message should say, so whatever we add has to stay legible to them. They have asked twice for the rejected rows and their reasons to be visible in the file rather than "somewhere in the JavaScript".
src/price-import.js already implements both behaviours; this is missing
coverage, not a missing feature.
Add coverage to features/price-import.feature and its step definitions for:
sku,qty,price, which must be refused outright with
the message Missing columns: quantity.Constraints:
features/step_definitions/.src/price-import.js must not change.Extract the following files before beginning.
=============== FILE: features/price-import.feature =============== Feature: Supplier price import
Scenario: A single valid row is imported Given a supplier file listing "BOOK-001" with quantity 4 at $12.50 When the file is imported Then the import accepts 1 row And nothing is rejected
=============== FILE: features/step_definitions/import.steps.js =============== const assert = require('node:assert'); const { Given, When, Then } = require('@cucumber/cucumber'); const { importRows } = require('../../src/price-import');
Given('a supplier file listing {string} with quantity {int} at ${float}', function (sku, quantity, price) { this.rows = [{ sku, quantity, price }]; });
When('the file is imported', function () { this.result = importRows(this.rows); });
Then('the import accepts {int} row(s)', function (count) { assert.strictEqual(this.result.imported.length, count); });
Then('nothing is rejected', function () { assert.strictEqual(this.result.rejected.length, 0); });
=============== FILE: src/price-import.js =============== const REQUIRED = ['sku', 'quantity', 'price'];
function checkHeader(csv) {
const columns = csv.trim().split('\n')[0].split(',').map((column) => column.trim());
const missing = REQUIRED.filter((column) => !columns.includes(column));
if (missing.length) return { accepted: false, message: Missing columns: ${missing.join(', ')} };
return { accepted: true };
}
function importRows(rows) { const imported = []; const rejected = []; for (const { sku, quantity, price } of rows) { if (!Number.isInteger(quantity) || quantity <= 0) { rejected.push({ sku, reason: 'Quantity must be a whole number above zero' }); } else if (typeof price !== 'number' || price <= 0) { rejected.push({ sku, reason: 'Price must be above zero' }); } else { imported.push({ sku, quantity, price }); } } return { imported, rejected }; }
module.exports = { checkHeader, importRows };
=============== FILE: cucumber.js =============== module.exports = { default: { require: ['features/step_definitions//*.js', 'features/support//*.js'], format: ['progress'], }, };
=============== FILE: package.json =============== { "name": "price-import-specs", "private": true, "scripts": { "bdd": "cucumber-js" }, "devDependencies": { "@cucumber/cucumber": "^10.9.0" } }