Introduction
In my previous post we installed Cypress, which also installed a number of Cypress sample tests. These sample tests use the Mocha syntax. In this post I'm going to talk about how to define your tests with feature files instead of Mocha. The examples will also leverage the page objects created in the previous post.
Before we get to the demo, I want to briefly discuss Gherkin and Cucumber.
Gherkin
Gherkin and Cucumber are concepts that you'll hear when talking about Behavior Driven Design (BDD). BDD is not meant as a testing framework, but as a process that encourages communication and collaboration among business, development, and testing folks.
This collaboration occurs when we begin defining new requirements and stories, and uses concrete examples of user interaction and application responses. The "language" used to define these examples is called gherkin, but ultimately it's written in a manner that's understood by all, including the business. I wrote a blog post awhile back that talks more about best practices around Gherkin.
Feature files are just the text files that contain the various concrete examples that were written in Gherkin.
Cucumber
Cucumber comes into play when we want to build tests that automate the Gherkin stories. Cucumber is implemented for a number of frameworks and languages. My simplistic definition of Cucumber is "software that allows us to tie gherkin-based requirements to test automation code".
For this demo I'll use cypress-cucumber-preprocessor, a Node package specifically developed to support feature files in Cypress.
Ok, it's time to write some code!
Setup
For this example I'm adding feature files to test the Cypress to-do sample app, and I will be converting one of the Cypress spec file tests to a feature file.
If you want to follow along with this example, take a look at the Setup section of my previous post, Using Page Object in Cypress
Adding Cucumber support to the project is a relatively easy task with the help of cypress-cucumber-preprocessor. Here are the steps:
- Install cypress-cucumber-preprocessor ```
npm install --save-dev cypress-cucumber-preprocessor
2. Add cypress-cucumber-preprocessor to the `integration/plugins/index.js`
javascript
const cucumber = require('cypress-cucumber-preprocessor').default
module.exports = (on, config) => {
on('file:preprocessor', cucumber())
}
3. Update cypress.json so Cypress knows that tests are contained in `.feature` files. I added feature files, and also decided to ignore the original sample tests that were installed with Cypress.
```javascript
{
"testFiles": "**/*.{feature,features,spec.js}",
"ignoreTestFiles": [
"**/1-getting-started/*.js",
"**/2-advanced-examples/*.js"
]
}
Create a feature file
I am going to be referencing some files that are found in my github repo, specifically in the 04-cucumber-examples branch. It might help to reference that repo as you read through this.
Let's take a look a the first first test in 3-page-object-examples/todo-po-class-spec.js
:
beforeEach(() => {
todoPage.navigateToHome();
})
it('displays two todo items by default', () => {
todoPage.validateTodoCount(2)
todoPage.validateTodoText(1, 'Pay electric bill')
todoPage.validateTodoText(2, 'Walk the dog')
})
As you can see, we're navigating to the home page, then validating the ToDo count and ToDo content. In gherkin, it might look something like this:
Feature: a sample feature to practice my testing
Scenario: displays two todo items by default
When I open the to-do page
Then 2 to-do items are displayed
And to-do item 1 is "Pay electric bill"
And to-do item 2 is "Walk the dog"
Note I said "it might look something like this". Other than some keywords, the scenario should be written in a common language that makes sense to all. I don't like those 2 hardcoded ToDo's, but I am going to try and ignore that for now since the point of this post is just to show you how to use feature files with Cypress.
Now I just need to create a .feature
file and put it somewhere in the integration
folder. You can paste the above scenario into a new file namedintegration/Sample.feature
Create a step definition file
So now we have a feature file, and we already had a page object, but we need to tie them together. That's where the step file comes in. Each step in your Gherkin scenario will need to match to a step in a step file. The step file will then call the appropriate page object.
The location of your step files is configurable based on a number of factors. Take a look at the doco for cypress-cucumber-preprocessor to get more info. I have things setup to put my feature files in the support/step_definitions
folder.
Let's focus on the first step of the scenario:
When I open the to-do page
To create the step file for this step, I'm just going to create file support/step_definitions/to-do-steps.js
and paste the following:
import { TodoPage } from "../../page-objects/todo-page"
import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";
const todoPage = new TodoPage()
When('I open the to-do page', () => {
todoPage.navigateToHome();
})
Hopefully it's pretty clear what's gong on here. We are importing the todo-page object and step syntax from cypress-cucumber-preprocessor. The step in the step file matches the step in the gherkin, so it will call navigateToHome()
in the page object.
Running our cucumber tests
So we implemented our feature file and steps file, let's run the feature file:
npx cypress run --spec "cypress/integration/**/Sample.feature"
If things work as expect, you should see error:
Error: Step implementation missing for: 2 to-do items are displayed
That's what you want to see. We have only implemented the first step of our test scenario. To get a green test and verify the first step is working, let's comment out the steps we haven't implemented and run again:
Feature: a sample feature to practice my testing
Scenario: displays two todo items by default
When I open the to-do page
# Then 2 to-do items are displayed
# And to-do item 1 is "Pay electric bill"
# And to-do item 2 is "Walk the dog"
Hopefully when you run npx cypress run --spec "cypress/integration/**/sample.feature"
you see a green test. Once it's green you can move ahead more quickly to implement steps for the others, following the same pattern.
Of course the first one is always the most difficult. If things are still not green, you will probably need to resort to reading the error messages. You can also look at my github repo to find differences.
Wrap-up
Well I hope you found some value in this post. Writing this post took longer than I expected, and I still feel like I have not gone into enough detail. If you have any questions or suggestions, please feel free to leave comments or contact me.
Feel free to subscribe to my blog site for more test automation content. Thanks!