JSFoo Pune 2019
End-to-End testing made easy with Nightwatch
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
Why use Nightwatch.js ?
Features
- Clean Syntax
- Built-in test runner
- Selenium server
- Cloud services support
- CSS & Xpath support
- Continous integration support
- Easy to extend
Community
Nightwatch.js has great community it has
-
85,375+ weekly downloads from
npm - 8,800+ stars
- 800+ forks
Great Documentation
Nightwatch.js uses the W3C WebDriver API, but it protects you from the very verbose and cryptic documentation of W3C WebDriver
vs
Getting Started
Pre-Requisites
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 || 'JSFoo Pune 2019',
};
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 JSFoo Pune 2019': 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('JSFoo Pune 2019 - JSFoo + Meta Refresh 2018')
.saveScreenshot('screenshots/JSFoo_Pune_2019_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 Commands
You can handle WindowEventHandlers using custom commands in your tests.
This might be helpful if you have a flow where you ask your user to confirm before leaving the page.
Custom Commands
// A custom Nightwatch command.
// The command name is the filename.
// Example usage:
//
// browser.hasOnBeforeUnload(function(result) {})
//
// For more information on custom assertions see:
// http://nightwatchjs.org/guide/#writing-custom-commands
module.exports.command = function(callback) {
var self = this;
this.execute(function() {
return window && typeof window.onbeforeunload === 'function';
}, [], function(result) {
callback.call(self, result.value);
});
return this;
};
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.
Custom Assertions
For example if you want to know how many elements of a particular kind are present on the page.
This maybe useful if you are building a pagination with multiple options to select number of items in a page.
Custom Assertions
// A custom Nightwatch assertion.
// The assertion name is the filename.
// Example usage:
//
// browser.assert.elementCount(selector, count)
//
// For more information on custom assertions see:
// http://nightwatchjs.org/guide#writing-custom-assertions
exports.assertion = function elementCount (selector, count) {
this.message = `Testing if element <${selector}> has count: ${count}`
this.expected = count
this.pass = val => val === count
this.value = res => res.value
function evaluator (_selector) {
return document.querySelectorAll(_selector).length
}
this.command = cb => this.api.execute(evaluator, [selector], cb)
}
{
"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 @ JSFoo Pune 2019
By Ratan Kulshreshtha
End-to-End testing made easy with Nightwatch @ JSFoo Pune 2019
- 1,082