DevConf.IN 2018

End-to-End testing made easy with Nightwatch

Ratan Kulshreshtha

@RatanShreshtha

Hi, I'm Ratan Kulshreshtha

  • IT Developer at Telstra India
  • Pythonista and Djangonaut
  • Linux User
  • Love Vue.js
  • Rustacean
  • Twitter, GitHub: @RatanShreshtha

What And Why?

  • End-to-End (E2E) testing solution for browser-based apps and websites.
  • Based on Node.js and selenium

What?

Why?

  • Testing is crucial
  • Find Bugs
  • Validation & verification
  • Feedback
  • E2E Testing lets you test and experiences an end user the complete system

Features

  • Clean Syntax
  • Built-in test runner
  • Selenium server
  • Cloud services support
  • CSS & Xpath support
  • Continous integration support
  • Easy to extend

Getting Started

Pre-Requisites

  • Node.js
  • Java
  • Terminal or CMD
  • Text Editor of your Choice

Installation

$ npm install [-g] nightwatch
Add -g option to make nightwatch runner available globally in your system

Selenium Server Setup

$ # For sanity check  
$ java -jar selenium-server-standalone-3.13.0.jar

Configuration

Test runner expects a configuration file to be passed, by default a nightwatch.json. A nightwatch.conf.js file will also be loaded by if found.

{
  "src_folders" : ["tests"],
  "output_folder" : "reports",
  "custom_commands_path" : "",
  "custom_assertions_path" : "",
  "page_objects_path" : "",
  "globals_path" : "",

  "selenium" : {
    "start_process" : false,
    "server_path" : "",
    "log_path" : "",
    "port" : 4444,
    "cli_args" : {
      "webdriver.chrome.driver" : "",
      "webdriver.gecko.driver" : "",
      "webdriver.edge.driver" : ""
    }
  },

  "test_settings" : {
    "default" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4444,
      "selenium_host"  : "localhost",
      "silent": true,
      "screenshots" : {
        "enabled" : false,
        "path" : ""
      },
      "desiredCapabilities": {
        "browserName": "firefox",
        "marionette": true
      }
    },

    "chrome" : {
      "desiredCapabilities": {
        "browserName": "chrome"
      }
    },

    "edge" : {
      "desiredCapabilities": {
        "browserName": "MicrosoftEdge"
      }
    }
  }
}

Writing Your First Test

Make a file 01_hello_world.js in tests directory

module.exports = {
  tags: ['hello_world'],
  'Hello, World!': function(browser) {
    browser
      .url('http://www.google.co.in') // Go to a url
      .waitForElementVisible('body', 2000) // wait till page loads
      .assert.title('Google') // Make sure Site title matches
      .assert.visible('input[type=text]')
      .setValue('input[type=text]', 'Hello, World!') // send values
      .waitForElementVisible('input[name=btnK]', 1000)
      .click('input[name=btnK]') // click on search button
      .pause(4000)
      .assert.containsText('#main', 'Hello, World!')
      .end();
  }
};
$ # If Installed globally
$ nightwatch -c ./nightwatch.json --env default
$ # If Installed locally
$ ./node_modules/nightwatch/bin/nightwatch -c nightwatch.json --env default

Running nightwatch

Test Results

Commands

clearValue
click
deleteCookie
deleteCookies
end
getAttribute
getCookie
getCookies
getCssProperty
getElementSize
getLocation
getLocationInView
getTagName
getText
getTitle
getValue
init
injectScript
isVisible
maximizeWindow
moveToElement
pause
resizeWindow
saveScreenshot
setCookie
setValue
submitForm
switchWindow
urlHash
waitForElementNotPresent
waitForElementNotVisible
waitForElementPresent
waitForElementVisible

Assertions

attributeEquals
containsText
cssClassPresent
cssClassNotPresent
cssProperty
elementPresent
elementNotPresent
hidden
title
urlContains
value
valueContains
visible

Data Driven Tests

To avoid hard-coding the values create a directory named data or any other directory for storing data.

 

Then specify the path to that folder inside the nightwatch.json file, as the globals_path property.

No Hardcoding

module.exports = {
  url: 'https://www.google.co.in/',
  searchKeyword: process.env.searchKeyword || 'DevConf.In 2018',
};

Make a .js file and export all the data

{
  "src_folders": ["tests"],
  "output_folder": "reports",
   ....
   ....
  "globals_path": "data/google",
   ....
   ....
}

nightwatch.json

Then access the data as browser.globals in your tests.

module.exports = {
  tags: ['google_data_driven'],
  'Google DevConf.In 2018': function(browser) {
    browser
      .url(browser.globals.url) // Go to a url
      .waitForElementVisible('body', 2000) // wait till page loads
      .assert.title('Google')  // Make sure Site title matches
      .saveScreenshot('screenshots/google_home_page,png')
      .assert.visible('input[type=text]')
      .setValue('input[type=text]', browser.globals.searchKeyword)
      .waitForElementVisible('input[name=btnI]', 1000)
      .click('input[name=btnI]') // click on search button
      .pause(5000)
      .waitForElementVisible('body', 2000)
      .assert.title('DevConf.IN | August 4-5, 2018 - Bengaluru, India')
      .saveScreenshot('screenshots/DevConf_IN_home_page.png')
      .end();
  }
};

Use the data in tests

Customisation

Custom Commands

To make custom nightwatch command create a separate folder and defining your own commands inside there, each one inside its own file.

 

Then specify the path to that folder inside the nightwatch.json file, as the custom_commands_path property.

Custom Assertions

Nightwatch allows you to even define your own assertions, extending the available .assert and .verify namespaces.

 

Make a folder where you have your custom assertions then specify the path to that folder inside the nightwatch.json file, as the custom_assertions_path property.

{
  "src_folders": ["tests"],
  "output_folder": "reports",
  "page_objects_path": "pages",
  "custom_assertions_path": "custom-assertions",
  "custom_commands_path": "custom-commands",
   ....
   ....
   ....
   ....
}

nightwatch.json

Demo

Let's Pray To Demo Gods

Resources

Thank You!

Questions And Feedback

End-to-End testing made easy with Nightwatch @ DevConf.IN 2018

By Ratan Kulshreshtha

End-to-End testing made easy with Nightwatch @ DevConf.IN 2018

  • 828