Setting Up Your Environment

Before we dive into writing tests, let's set up our environment. Ensure you have Node.js installed, then create a new project directory and initialize it with npm.

mkdir bdd-example
cd bdd-example
npm init -y

Next, install Cucumber.js and any other dependencies you might need:

npm install --save-dev @cucumber/cucumber chai

Writing Your First Feature

Cucumber.js uses Gherkin language to define features and scenarios. Create a new directory called features and inside it, create a file named calculator.feature. This file will describe the behavior of a simple calculator.

Feature: Calculator

  Scenario: Add two numbers
    Given I have a calculator
    When I add 5 and 3
    Then the result should be 8

  Scenario: Subtract two numbers
    Given I have a calculator
    When I subtract 5 from 10
    Then the result should be 5

Implementing Step Definitions

Step definitions are where the actual code is written to execute the steps defined in your feature file. Create a new directory called step_definitions and add a file named calculatorSteps.js.

const { Given, When, Then } = require('@cucumber/cucumber');
const { expect } = require('chai');

let calculator;
let result;

Given('I have a calculator', function () {
  calculator = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
  };
});

When('I add {int} and {int}', function (a, b) {
  result = calculator.add(a, b);
});

When('I subtract {int} from {int}', function (b, a) {
  result = calculator.subtract(a, b);
});

Then('the result should be {int}', function (expectedResult) {
  expect(result).to.equal(expectedResult);
});

Running Your Tests

To execute your tests, add a script to your package.json:

"scripts": {
  "test": "cucumber-js"
}

Now, run the tests using the following command:

npm test

You should see output indicating that the scenarios have passed.

Organizing Your Project

As your project grows, it’s essential to keep it organized. Consider the following structure:

/bdd-example
  ├── /features
  │   └── calculator.feature
  ├── /step_definitions
  │   └── calculatorSteps.js
  └── package.json

Best Practices for BDD with Cucumber.js

  1. Keep Scenarios Simple: Each scenario should test one specific behavior. This makes it easier to understand and maintain.
  2. Use Natural Language: Write your feature files in a way that stakeholders can easily read and understand.
  3. Parameterize Steps: Use placeholders in your step definitions (like {int}) to make them reusable.
  4. Avoid Overlapping Scenarios: Ensure that scenarios are distinct to prevent confusion and maintain clarity.
  5. Regularly Review Features: Collaborate with your team to review and refine feature files, ensuring they remain relevant.

Advanced Features of Cucumber.js

Cucumber.js also supports advanced features such as hooks and tags. Hooks allow you to run code before or after scenarios, while tags can help you organize and filter scenarios when running tests.

Example of Hooks

You can use hooks to set up or tear down your test environment. Create a new file named hooks.js in the step_definitions directory.

const { Before, After } = require('@cucumber/cucumber');

Before(function () {
  // Code to set up test environment
});

After(function () {
  // Code to clean up after tests
});

Example of Tags

You can tag scenarios in your feature file to run specific tests. Modify your calculator.feature to include tags:

@calculator
Feature: Calculator

  @addition
  Scenario: Add two numbers
    Given I have a calculator
    When I add 5 and 3
    Then the result should be 8

  @subtraction
  Scenario: Subtract two numbers
    Given I have a calculator
    When I subtract 5 from 10
    Then the result should be 5

To run only the scenarios tagged with @addition, use the following command:

npx cucumber-js --tags @addition

Conclusion

Implementing Behavior-Driven Development with Cucumber.js in JavaScript allows teams to create a shared understanding of application behavior through clear and concise feature files. By following best practices and leveraging advanced features, you can enhance collaboration and ensure your tests remain maintainable and effective.


Learn more with useful resources