Before starting this blog please make sure you've followed through the previous blog. This blog is the continuation of the previous one.
We will be using BDD for writing tests meaning we will be writing a feature file first. We will be using Gherkin to write feature files.
Through Gherkin, we can write test cases in the native language which will be easier to understand by everyone involved in the project whether they're from the technical field or not. I'm going to explain some of the keywords and their usage, that are used in this blog for further information please visit their official website
Keywords
-
Feature
: a short description about a software feature -
Scenario
: list of steps to describe a business rule
Syntax
Scenario: name of the scenario
Given [Preconditions or initial context of the system ]
When [Event or action]
Then [Expected output]
Write a feature file
Inside tests/acceptance/
folder make a folder name feature
. Inside this folder make a feature file named todo.feature
, we will be writing a scenario in this file.
The UI of the application that I'm writing test on looks like this
We can simply add todo items and remove them. For this blog, I'm going to write a test scenario for adding the item and checking if the item is displayed in the UI.
The feature file todo.feature
looks like this
Feature: todo
As a user
I want to add an item to the todo list
So that I can organize task
Scenario: Add item to the todo list
Given a user has navigated to the homepage
When the user adds "test" to the todo list using the webUI
Then card "test" should be displayed on the webUI
You can add multiple scenarios in the same feature file as per your need.
Step Definitions
After writing scenarios we need to implement them, for this, we will create stepDefinitions
. Create a folder stepDefinitions
inside tests/acceptance/
and inside setDefinitions
create a file todo.js
.
Add the following script in your package.json in the scripts section
"test:e2e": "cucumber-js --require tests/acceptance/cucumber.conf.js --require tests/acceptance/stepDefinitions"
We will use the test:e2e
script for running the test.
Run selenium server
Using docker:
docker run -d --network="host" -v /dev/shm:/dev/shm selenium/standalone-chrome-debug
using jar file: (inside the folder where your selenium server and chromedriver files are)
java -jar <name-of-seleniun-server-standalone>.jar -port 4444
Now go to your terminal and from inside the root directory of your project run the feature file using the following script
npm run test:e2e <path-to-yourfeature-file>
In my case
npm run test:e2e tests/acceptance/feature/todo.feature
The above script will run the whole feature, if you want to run a particular scenario you can and the line number of the scenario at last like so
npm run test:e2e tests/acceptance/feature/todo.feature:6
After running the feature file you will see an output similar to this in your terminal
Failures:
1) Scenario: Add item to todo list # tests/acceptance/feature/todo.feature:6
? Given a user has navigated to the homepage
Undefined. Implement with the following snippet:
Given('a user has navigated to the homepage', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? When the user adds "clean room" to the todo list using the webUI
Undefined. Implement with the following snippet:
When('the user adds {string} to the todo list using the webUI', function (string) {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? Then card "clean room" should be displayed on the webUI
Undefined. Implement with the following snippet:
Then('card {string} should be displayed on the webUI', function (string) {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
1 scenario (1 undefined)
3 steps (3 undefined)
0m00.001s (executing steps: 0m00.000s)
You can copy these code templates and paste in your todo.js
file. This is where we will write the implementation.
Given('a user has navigated to the homepage', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
First of all, import following in the file todo.js
const {Given, When, Then} = require('@cucumber/cucumber')
const {client} = require('nightwatch-api')
Now find the CSS or XPath selector of various elements that will be involved in the test.
//css selectors
const todoInputField = '.todo-input'
const todoCreateButton = '.todo-button'
const todoListItem = '.todo .todo-item'
You can do this by using the developer’s tool in the browser and inspecting each element you need.
You can also check if the element is correct by using console.
Given('a user has navigated to the homepage', function () {
return client.url("http://localhost:3000");
});
When('the user adds {string} to the todo list using the webUI', async function (item) {
await client.waitForElementVisible(todoInputField)
.click(todoInputField)
.setValue(todoInputField, item)
.click(todoCreateButton)
return client
});
Then('card {string} should be displayed on the webUI', function (item) {
return client.getText(todoListItem, function (result) {
this.assert.equal(result.value, item)
})
});
At the Given
step we navigated to the index page of our UI, this is the precondition. Each action that we perform to achieve certain output needs to be specified at the when
step and at the Then
step we check if the expected output
has been achieved or not. The API commands used can be found on the official website of nightwatch.
The whole code together looks like this
const {Given, When, Then} = require('@cucumber/cucumber')
const {client} = require('nightwatch-api')
//css selectors
const todoInputField = '.todo-input'
const todoCreateButton = '.todo-button'
const todoListItem = '.todo .todo-item'
Given('a user has navigated to the homepage', function () {
return client.url("http://localhost:3000");
});
When('the user adds {string} to the todo list using the webUI', async function (item) {
await client.waitForElementVisible(todoInputField)
.click(todoInputField)
.setValue(todoInputField, item)
.click(todoCreateButton)
return client
});
Then('card {string} should be displayed on the webUI', function (item) {
return client.getText(todoListItem, function (result) {
this.assert.equal(result.value, item)
})
});
Now you can run the test again and they should pass.
npm run test:e2e tests/acceptance/feature/todo.feature
> todo@0.1.0 test:e2e
> cucumber-js --require tests/acceptance/cucumber.conf.js --require tests/acceptance/stepDefinitions "tests/acceptance/feature/todo.feature"
ℹ Connected to localhost on port 4444 (328ms).
Using: chrome (87.0.4280.66) on linux platform.
..√ Element <.todo-input> was visible after 69 milliseconds.
.√ Passed [equal]: clean room == clean room
..
1 scenario (1 passed)
3 steps (3 passed)
0m06.385s (executing steps: 0m06.353s)
Voila, you have successfully written and implemented an acceptance test! You can add more tests and features as per your project and need. Hope this blog helped you!
You can find the source code here
Top comments (0)