Test Automation using NightWatch - Part 1

Nightwatch Examples

In this blog series, I’m going to show you what I’ve learned automating using NightwatchJs.

A NightwatchJs is an E2E testing framework used for automating browser web apps. It uses the W3C WebDriver API as the underlying to perform automation.

It has the built in test runner, which can run the tests even in parallel, by group and tags. It comes with the out-of-the box solution to execute tests on cloud testing services, such as SauceLabs and BrowserStack.

By default, it provides the JUnit XML report generated after the execution which is easy to integrate with the CI tools such as Jenkins, TeamCity and so on.

What are we going to automate?

We are going to automate The Internet website. While performing automation, we together solve problems / challenges.

Let’s start!

Pre-requisites

  • Node with NPM (I’m using Node v7.1.0 and npm v3.10.9)
  • (Optional) Yarn (I’m using Yarn v0.17.6)
  • Chrome browser (My chrome version is 57.0)

Sample code

This is an optional step. The example that we are going to see in this article are available in the github. Follow the steps to clone and run:

git clone https://github.com/email2vimalraj/nightwatch-example.git
cd nightwatch-example
yarn

Setup

Create a directory:

mkdir nightwatch-example
cd nightwatch-example

Initiate the node js project using:

yarn init

Accept all the default parameters which yarn prompts.

Install NightwatchJS as dev dependency using:

yarn add --dev nightwatch

Configuration

The nightwatch test runner uses the json file which is used as configuration for the test runner.

By default, if a file called nightwatch.json available in the current directory, test runner will pick it up.

Let’s create the following nightwatch.json in the project’s root directory:

{
  "src_folders": ["tests"],
  "output_folder": "reports",

  "test_settings": {
    "default": {
      "launch_url": "http://the-internet.herokuapp.com/",
      "desiredCapabilities": {
      "browserName": "chrome"
      }
    }
  }
}
  • src_folder - will contain a list of folders where the test scripts are placed. In this example, we’ll be keeping all our tests in the tests directory

  • output_folder - this config let’s you place the generated reports in the specified directory. Here, the reports will be generated in the reports directory.

  • test_settings - This will contain all test related settings, in other words, we can have settings for each different environment. The default is mandatory and a default setting used by tests.

  • launch_url - Let’s you define the default url that we use to automate. We’ll look further on how we use this setting.

  • desiredCapabilities - It is the Webdriver’s desired capabilities configuration. Here we’re using Chrome as the default browser for our automation.

Chromedriver setup

There are two ways to configure Chromedriver to automate on the chrome browser.

  • Using Selenium Server (requires Java)
  • Using Standalone (no dependency on Java)

In this example, we will be using the Standalone usage since there is no dependency on Java. But it requires a one-time configuration. Let’s install the ChromeDriver npm package:

yarn add --dev chromedriver

Then disable the selenium server in the nightwatch.json file by adding the following configuration at the end:

"selenium": {
  "start_process": false
}

Then in the test_settings configuration, we’ll have to configure the selenium port and host since the default port used by chromedriver is 9515. Let’s update the test_settings config:

"selenium_port": 9515,
"selenium_host": "localhost",
"default_path_prefix": ""

We have to clear the default_path_prefix, as it is by default set to /wd/hub which chromedriver doesn’t require it.

Create a chrome driver global file

A global file is the js file which will be loaded by the test runner and made available to the test. We’ll be using this file to start the chromedriver before the test starts and quits the chromedriver after the test finishes its execution.

Let’s create a file called chromedriver.global.js:

var chromedriver = require('chromedriver')

module.exports = {
  before: function(done) {
    chromedriver.start()
    done()
  },

  after: function(done) {
    chromedriver.stop()
    done()
  }
}

Now we’ll have to load this file through the configuration file. Add the following config at the end of the nightwatch.json:

"globals_path": "./chromedriver.global.js"

Our nightwatch.json should look like this now:

{
  "src_folders": ["tests"],
  "output_folder": "reports",

  "selenium": {
    "start_process": false
  },

  "test_settings": {
    "default": {
      "launch_url": "http://the-internet.herokuapp.com/",
      "selenium_port": 9515,
      "selenium_host": "localhost",
      "default_path_prefix": "",
      "desiredCapabilities": {
        "browserName": "chrome"
      }
    }
  },

  "globals_path": "./chromedriver.global.js"
}

Create our first test

Let’s create a HomeTest.js file in the tests directory:

module.exports = {
  'Test Home Page': function(client) {
    client.init()
    client.waitForElementVisible('body', 1000)
    client.assert.title('The Internet')
    client.expect.element('.heading').text.to.equal('Welcome to the Internet')
    client.end()
  }
}

Each file in the tests directory is considered as test suite. Here, in the HomeTest.js we have created one test called Test Home Page. Each test function will have one parameter which holds the webdriver instance. Here, we are calling that instance as client. All the nightwatch webdriver commands are accessed through this instance.

The client.init() will launch the browser with the url configured in the launch_url property in the nightwatch.json. In our case, it will open the chrome browser and launch http://the-internet.herokuapp.com/.

Then it will wait for the body tag to be visible for maximum of 1 sec. After that we assert the title to be equal to The Internet. Then we expect an element with class attribute .heading and with text to be equal to Welcome to the Internet.

The client.end() is mandatory to close the browser instance and stop the selenium server instance.

Let’s execute our first test. Spin off your terminal / command prompt, and execute your test as follows:

./node_modules/.bin/nightwatch

This should execute your tests and you can watch the result in your console:

[home test] Test Suite
==========================

Running: Test Home Page
✔ Element <body> was visible after 44 milliseconds.
✔ Testing if the page title equals "The Internet".
✔ Expected element <.heading> text to equal: "Welcome to the Internet"

OK. 3 assertions passed. (20.669s)

Awesome, we successfully created our test and executed. Let’s add one more test:

module.exports = {
  'Test Home Page': function(client) {
    client.init()
    client.waitForElementVisible('body', 1000)
    client.assert.title('The Internet')
    client.expect.element('.heading').text.to.equal('Welcome to the Internet')
  },

  'Navigate to Broken Images page': function(client) {
    client.click("a[href='/broken_images']")
    client.expect.element('.example > h3').text.to.equal('Broken Images')
    client.end()
  }
}

Here we have added another test called Navigate to Broken Images page in which we navigate to the Broken Images page and assert the heading. Note that we have removed the client.end() from the first test and moved that to the second test.

Execute again and see both of your tests run.

Finally, we have two tests which runs successfully.

In the next part, we’ll make our tests more maintainable using page object pattern.