3 COMMON WAYS OF SETTING UP A BDD ENVIRONMENT WITH CUCUMBER.

Jacob Nuwamanya
7 min readMay 5, 2021

Prerequisite: This article assumes you have some knowledge about BDD and cucumber-js, it is solely focused on the different ways of structuring your project and doesn’t provide a step by step process on how to use cucumber. If you are new to BDD here is an article from sitepoint that can guide you.

BDD (Behavioral Driven Development) is a part of TDD (Test Driven Development) that uses human-readable descriptions of user requirements. For example, as a calculator user, if I add 1 + 1, then I expect to get 2. A BDD test, will check if the calculator software does what the user expects.

BDD testing, is a very important part of software development, it enables you to prioritize your development, through collaboration of the business and technology side of any team. The business side always knows more about user requirements because they are in direct contact with the users and as such have great insight in what will bring more value to the software users.

Therefore, it important for every software developer, to learn how to carry out BDD tests to facilitate this collaboration and produce great value for the users.

In this article, I try to give context to the inner workings of cucumber and how you can set up your project structure.

What you need to follow the content in this article?

· A node.js installation on your computer. You can check if you have it installed by typing node -v or node --version in your terminal. The result, if installed, is the version currently running.

· A text editor of your choice. The screen shots you will look at are of VS Code.

· Knowledge on how to use node and npm.

Let us create a node project

· Create and initialize a node project anywhere on your machine, install and save cucumber as a dev dependency.

npm install @cucumber/cucumber --save-dev

As of this writing, the current version is 7.0.0

· Create a tests directory within the root of your project directory. This directory will hold all our BDD related test files in this example.

This below, should be your current structure.

Method 1: Features and steps files in the same directory

Create your features and step definition files within the tests directory. For this example, I will create an addition.feature file plus a steps.js file. You can use any files of your choice.

Within your package.json, name your scripts as “cucumber” (or any name of your choice) with its value as cucumber-js ./tests/

Before we get into the explanation, this is my current file structure and package.json reflecting the new changes.

By design, the string value assigned to cucumber on line 7 has three main parts;

· The execution file (cucumber-js)

· The location of the features files

· The location of the steps definition files (optional under certain conditions)

So what does line 7 in our package.json file mean?

First we have a named script that can now be referenced with the name ‘cucumber’ but most importantly is the value assigned to this name and let’s break it down.

cucumber-js:

This is a file stored within the node_modules/.bin directory and it manages the execution and path details for cucumber.

In some examples, you will notice in the place of cucumber-js, a relative path ./node_modules/.bin/cucumber-js the final result is the same.

./tests/

This points cucumber to the location of our feature files.

This is where it gets interesting and the distinction between the three methods starts to take shape.

How cucumber works

By default, cucumber assumes that your step definition files are within the same directory as your feature files.

Therefore, when one doesn’t explicitly define the location of the step definition files, then cucumber will search the current directory defined as the location for the feature files to find the step definition files.

Method 1 takes advantage of this and simply points cucumber to the tests directory as the location of our feature files and lets it work in its default state.

In some case, you will notice code that adds an extra argument to path pointing to the feature files.

In my experience, this only makes the path more readable. The code snippet above makes it abundantly clear that we are targeting files with a .feature extension, however, it has no effect on cucumber-js execution.

By design, cucumber is aware that the first path is pointing to the location of the feature files and it will search that directory for files with the .feature file extension.

However, I recognize why some people may feel the need to add the extra argument. Having all your feature and step definition files in the same directory is not a clean and neat way of doing things. So let’s look at method 2

Method 2: Step definition files in a sub-directory within the directory holding our feature files.

Create a sub-directory ‘steps’ in the tests directory and move the steps.js file into it.

Notice how the script command on line 7 has not changed at all.

This points back to how cucumber works, by default, it will search the defined location of the feature files to find the step definition files.

It doesn’t matter how deeply nested (well, I only tested it with the steps.js file nested two layers deeper) your steps.js file is as long as the containing sub-directory is within the same directory holding the feature files.

Method 2 gives us some form of structure by separating the step definition files from the feature files, however, the feature files are still located directly within the tests directory.

In the event you want to add other tests maybe TDD tests using mocha, chai then you will have a bit of a mess.

This brings us to method 3 which should completely address the structural issues and separation of files.

Method 3: Feature and step definition files in separate sub-directories within the tests directory

Create a sub-directory ‘features’ and move the addition.feature file into it.

So many changes on line 7 in the package.json file. Let’s break them down.

Firstly, we created a sub-directory features and moved our addition.feature file into it. This change therefore means our feature files are no longer in the tests directory so we have to make changes to the path that tells cucumber where to find the feature files.

We do this by adding /features/ to the path. Our new path pointing to the location of our features files therefore is ./tests/features/

Secondly, by moving the feature files into a separate directory, it means that the default cucumber execution style won’t work. When cucumber tries to search for the steps.js file within the location of the feature files, it won’t be able to find them.

We address this by using the -r flag followed by the path pointing to the location of our steps.js file.

Using -r or --requiretells cucumber to require the files at the specified location before executing the features.

Personally, I prefer method 3 because it provides a clean and neat file structure that is easy to understand.

Here is what our file structure looks like when we re-arrange our files.

Conclusion.

I wrote this article to show you the different ways of setting up your project so you can always choose which one is best for you.

Extras.

You can find a list of all supported flags and their meanings by opening a terminal and typing this command

./node_modules/.bin/cucumber-js --help

Note: Make sure your path in the terminal ends with the directory name of your current project where cucumber is installed before you type that command.

Please do follow me on medium for tech related content or you can connect with me on linkedIn using the following;

Jacob Nuwamanya on LinkedIn

Jacob Nuwamanya on Medium

--

--

Jacob Nuwamanya

I build digital products with Nuxt -Vue -Node -Android & enjoy the thrill of learning new things.