How to automate tests for your website using Nightwatch.js? - Part 2- Writing tests
Tags: javascript, qa, nightwatch, testing
Published: 2021-12-03 12:55:51




Before starting this blog please make sure you've followed through the previous [blog](https://dev.to/swikritit/how-to-automate-tests-for-your-website-using-nightwatchjs-part-1-setting-up-nightwatch-53m4). 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](https://cucumber.io/docs/gherkin/reference/) to write feature files. 

Through [Gherkin](https://cucumber.io/docs/gherkin/reference/), 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](https://cucumber.io/docs/gherkin/reference/)

## 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


![UI of a todo app with input fileds and add button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ua3oo7bshnttuyrrfuxd.png)




![UI of a todo app with an item added in the list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zcgl2e1pia0qnv262xyl.png)

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. 


![inspecting an element using developer's tool](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gv7r75ra46w9spe5s1z5.png)

You can also check if the element is correct by using console.

![making sure the element element is correct by printing it in console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytidl976wkfpygtjjhia.png)
Now we implement the steps.
```
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](https://nightwatchjs.org/api/).

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](https://github.com/SwikritiT/todo/tree/nightwatch-testing)