• United States+1
  • United Kingdom+44
  • Afghanistan (‫افغانستان‬‎)+93
  • Albania (Shqipëri)+355
  • Algeria (‫الجزائر‬‎)+213
  • American Samoa+1684
  • Andorra+376
  • Angola+244
  • Anguilla+1264
  • Antigua and Barbuda+1268
  • Argentina+54
  • Armenia (Հայաստան)+374
  • Aruba+297
  • Australia+61
  • Austria (Österreich)+43
  • Azerbaijan (Azərbaycan)+994
  • Bahamas+1242
  • Bahrain (‫البحرين‬‎)+973
  • Bangladesh (বাংলাদেশ)+880
  • Barbados+1246
  • Belarus (Беларусь)+375
  • Belgium (België)+32
  • Belize+501
  • Benin (Bénin)+229
  • Bermuda+1441
  • Bhutan (འབྲུག)+975
  • Bolivia+591
  • Bosnia and Herzegovina (Босна и Херцеговина)+387
  • Botswana+267
  • Brazil (Brasil)+55
  • British Indian Ocean Territory+246
  • British Virgin Islands+1284
  • Brunei+673
  • Bulgaria (България)+359
  • Burkina Faso+226
  • Burundi (Uburundi)+257
  • Cambodia (កម្ពុជា)+855
  • Cameroon (Cameroun)+237
  • Canada+1
  • Cape Verde (Kabu Verdi)+238
  • Caribbean Netherlands+599
  • Cayman Islands+1345
  • Central African Republic (République centrafricaine)+236
  • Chad (Tchad)+235
  • Chile+56
  • China (中国)+86
  • Christmas Island+61
  • Cocos (Keeling) Islands+61
  • Colombia+57
  • Comoros (‫جزر القمر‬‎)+269
  • Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)+243
  • Congo (Republic) (Congo-Brazzaville)+242
  • Cook Islands+682
  • Costa Rica+506
  • Côte d’Ivoire+225
  • Croatia (Hrvatska)+385
  • Cuba+53
  • Curaçao+599
  • Cyprus (Κύπρος)+357
  • Czech Republic (Česká republika)+420
  • Denmark (Danmark)+45
  • Djibouti+253
  • Dominica+1767
  • Dominican Republic (República Dominicana)+1
  • Ecuador+593
  • Egypt (‫مصر‬‎)+20
  • El Salvador+503
  • Equatorial Guinea (Guinea Ecuatorial)+240
  • Eritrea+291
  • Estonia (Eesti)+372
  • Ethiopia+251
  • Falkland Islands (Islas Malvinas)+500
  • Faroe Islands (Føroyar)+298
  • Fiji+679
  • Finland (Suomi)+358
  • France+33
  • French Guiana (Guyane française)+594
  • French Polynesia (Polynésie française)+689
  • Gabon+241
  • Gambia+220
  • Georgia (საქართველო)+995
  • Germany (Deutschland)+49
  • Ghana (Gaana)+233
  • Gibraltar+350
  • Greece (Ελλάδα)+30
  • Greenland (Kalaallit Nunaat)+299
  • Grenada+1473
  • Guadeloupe+590
  • Guam+1671
  • Guatemala+502
  • Guernsey+44
  • Guinea (Guinée)+224
  • Guinea-Bissau (Guiné Bissau)+245
  • Guyana+592
  • Haiti+509
  • Honduras+504
  • Hong Kong (香港)+852
  • Hungary (Magyarország)+36
  • Iceland (Ísland)+354
  • India (भारत)+91
  • Indonesia+62
  • Iran (‫ایران‬‎)+98
  • Iraq (‫العراق‬‎)+964
  • Ireland+353
  • Isle of Man+44
  • Israel (‫ישראל‬‎)+972
  • Italy (Italia)+39
  • Jamaica+1876
  • Japan (日本)+81
  • Jersey+44
  • Jordan (‫الأردن‬‎)+962
  • Kazakhstan (Казахстан)+7
  • Kenya+254
  • Kiribati+686
  • Kosovo+383
  • Kuwait (‫الكويت‬‎)+965
  • Kyrgyzstan (Кыргызстан)+996
  • Laos (ລາວ)+856
  • Latvia (Latvija)+371
  • Lebanon (‫لبنان‬‎)+961
  • Lesotho+266
  • Liberia+231
  • Libya (‫ليبيا‬‎)+218
  • Liechtenstein+423
  • Lithuania (Lietuva)+370
  • Luxembourg+352
  • Macau (澳門)+853
  • Macedonia (FYROM) (Македонија)+389
  • Madagascar (Madagasikara)+261
  • Malawi+265
  • Malaysia+60
  • Maldives+960
  • Mali+223
  • Malta+356
  • Marshall Islands+692
  • Martinique+596
  • Mauritania (‫موريتانيا‬‎)+222
  • Mauritius (Moris)+230
  • Mayotte+262
  • Mexico (México)+52
  • Micronesia+691
  • Moldova (Republica Moldova)+373
  • Monaco+377
  • Mongolia (Монгол)+976
  • Montenegro (Crna Gora)+382
  • Montserrat+1664
  • Morocco (‫المغرب‬‎)+212
  • Mozambique (Moçambique)+258
  • Myanmar (Burma) (မြန်မာ)+95
  • Namibia (Namibië)+264
  • Nauru+674
  • Nepal (नेपाल)+977
  • Netherlands (Nederland)+31
  • New Caledonia (Nouvelle-Calédonie)+687
  • New Zealand+64
  • Nicaragua+505
  • Niger (Nijar)+227
  • Nigeria+234
  • Niue+683
  • Norfolk Island+672
  • North Korea (조선 민주주의 인민 공화국)+850
  • Northern Mariana Islands+1670
  • Norway (Norge)+47
  • Oman (‫عُمان‬‎)+968
  • Pakistan (‫پاکستان‬‎)+92
  • Palau+680
  • Palestine (‫فلسطين‬‎)+970
  • Panama (Panamá)+507
  • Papua New Guinea+675
  • Paraguay+595
  • Peru (Perú)+51
  • Philippines+63
  • Poland (Polska)+48
  • Portugal+351
  • Puerto Rico+1
  • Qatar (‫قطر‬‎)+974
  • Réunion (La Réunion)+262
  • Romania (România)+40
  • Russia (Россия)+7
  • Rwanda+250
  • Saint Barthélemy (Saint-Barthélemy)+590
  • Saint Helena+290
  • Saint Kitts and Nevis+1869
  • Saint Lucia+1758
  • Saint Martin (Saint-Martin (partie française))+590
  • Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)+508
  • Saint Vincent and the Grenadines+1784
  • Samoa+685
  • San Marino+378
  • São Tomé and Príncipe (São Tomé e Príncipe)+239
  • Saudi Arabia (‫المملكة العربية السعودية‬‎)+966
  • Senegal (Sénégal)+221
  • Serbia (Србија)+381
  • Seychelles+248
  • Sierra Leone+232
  • Singapore+65
  • Sint Maarten+1721
  • Slovakia (Slovensko)+421
  • Slovenia (Slovenija)+386
  • Solomon Islands+677
  • Somalia (Soomaaliya)+252
  • South Africa+27
  • South Korea (대한민국)+82
  • South Sudan (‫جنوب السودان‬‎)+211
  • Spain (España)+34
  • Sri Lanka (ශ්‍රී ලංකාව)+94
  • Sudan (‫السودان‬‎)+249
  • Suriname+597
  • Svalbard and Jan Mayen+47
  • Swaziland+268
  • Sweden (Sverige)+46
  • Switzerland (Schweiz)+41
  • Syria (‫سوريا‬‎)+963
  • Taiwan (台灣)+886
  • Tajikistan+992
  • Tanzania+255
  • Thailand (ไทย)+66
  • Timor-Leste+670
  • Togo+228
  • Tokelau+690
  • Tonga+676
  • Trinidad and Tobago+1868
  • Tunisia (‫تونس‬‎)+216
  • Turkey (Türkiye)+90
  • Turkmenistan+993
  • Turks and Caicos Islands+1649
  • Tuvalu+688
  • U.S. Virgin Islands+1340
  • Uganda+256
  • Ukraine (Україна)+380
  • United Arab Emirates (‫الإمارات العربية المتحدة‬‎)+971
  • United Kingdom+44
  • United States+1
  • Uruguay+598
  • Uzbekistan (Oʻzbekiston)+998
  • Vanuatu+678
  • Vatican City (Città del Vaticano)+39
  • Venezuela+58
  • Vietnam (Việt Nam)+84
  • Wallis and Futuna+681
  • Western Sahara (‫الصحراء الغربية‬‎)+212
  • Yemen (‫اليمن‬‎)+967
  • Zambia+260
  • Zimbabwe+263
  • Åland Islands+358
Thanks! We'll be in touch in the next 12 hours
Oops! Something went wrong while submitting the form.

Automation Testing with Nightwatch JS and Cucumber: Everything You Need to Know

Satabdi Sikdar

Full-stack Development

What is Nightwatch JS?

Nightwatch.js is a test automation framework on web applications, developed in Node.js which uses W3C WebDriver API (formerly Selenium WebDriver). It is a complete End-to-End testing solution which aims to simplify writing automated tests and setting up Continuous Integration. Nightwatch works by communicating over a restful HTTP API with a WebDriver server (such as ChromeDriver or Selenium Server). The latest version available in market is 1.0.

Nightwatch.Js

Why Use Nightwatch JS Over Any Other Automation Tool?

Selenium is demanded for developing automation framework since it supports various programming languages, provides cross-browser testing and also used in both web application and mobile application testing.

But Nightwatch, built on Node.js, exclusively uses JavaScript as the programming language for end-to-end testing which has the listed advantages -

  • Lightweight framework
  • Robust configuration
  • Integrates with cloud servers like SauceLabs and Browserstack for web and mobile testing with JavaScript, Appium
  • Allows configuration with Cucumber to build a strong BDD (Behaviour Driven Development) setup
  • High performance of the automation execution
  • Improves test structuring
  • Minimum usage and less Maintenance of code

Installation and Configuration of Nightwatch Framework

For configuring Nightwatch framework, all needed are the following in your system -

  • Download latest Node.js
  • Install npm

$ npm install
view raw install.sh hosted with ❤ by GitHub

  • Package.json file for the test settings and dependencies

$ npm init
view raw npm.sh hosted with ❤ by GitHub

  • Install nightwatch and save as dev dependency

$ npm install nightwatch --save-dev
view raw nightwatch_sh hosted with ❤ by GitHub

  • Install chromedriver/geckodriver and save as dev dependency for running the execution on the required browser

$ npm install chromedriver --save-dev

{
"name": "demotest",
"version": "1.0.0",
"description": "Demo Practice",
"main": "index.js",
"scripts": {
"test": "nightwatch"
},
"author": "",
"license": "ISC",
"devDependencies": {
"chromedriver": "^74.0.0",
"nightwatch": "^1.0.19"
}
}
view raw package.json hosted with ❤ by GitHub

  • Create a nightwatch.conf.js for webdriver and test settings with nightwatch

const chromedriver = require('chromedriver');
module.exports = {
src_folders : ["tests"], //tests is a folder in workspace which has the step definitions
test_settings: {
default: {
webdriver: {
start_process: true,
server_path: chromedriver.path,
port: 4444,
cli_args: ['--port=4444']
},
desiredCapabilities: {
browserName: 'chrome'
}
}
}
};

Using Nightwatch - Writing and Running Tests

We create a JavaScript file named demo.js for running a test through nightwatch with the command

$ npm test
view raw npm_test.sh hosted with ❤ by GitHub

//demo.js is a JS file under tests folder
module.exports = {
'step one: navigate to google' : function (browser) { //step one
browser
.url('https://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('input[name=btnK]', 1000)
},
'step two: click input' : function (browser) { //step two
browser
.click('input[name=btnK]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end(); //to close the browser session after all the steps
}
view raw demo.js hosted with ❤ by GitHub

This command on running picks the value “nightwatch” from “test” key in package.json file which hits the nightwatch api to trigger the URL in chromedriver.

There can be one or more steps in demo.js(step definition js) file as per requirement or test cases.

Also, it is a good practice to maintain a separate .js file for page objects which consists of the locator strategy and selectors of the UI web elements.

module.exports = {
elements: {
googleInputBox: '//input[@type="text"]',
searchButton: '(//input[@value="Google Search"])[2]',
headingText: `//h3[contains(text(),'Nightwatch.js')]`
}
}
view raw pageObjects.js hosted with ❤ by GitHub

The locator strategy is set to CSS and Xpath to inspect the UI elements.

locateStrategy: async function (selector) { return await selector.startsWith('/') ? 'xpath' : 'css selector'; }

Nightwatch.conf.js file is also updated with the page_objects location.

const chromedriver = require('chromedriver');
module.exports = {
src_folders : ["tests"], //tests is a folder in workspace which has the step definitions
page_objects_path: 'page_objects/', //page_objects folder where selectors are saved
test_settings: {
default: {
webdriver: {
start_process: true,
server_path: chromedriver.path,
port: 4444,
cli_args: ['--port=4444']
},
desiredCapabilities: {
browserName: 'chrome'
}
}
}
};

Nightwatch and Cucumber JS

Cucumber is a tool that supports Behavior Driven Development (BDD) and allows to write tests in simple english language in Given, When, Then format.

  • It is helpful to involve business stakeholders who can't easily read code
  • Cucumber testing focuses on covering the UI scenarios from end-user’s perspective
  • Reuse of code is easily possible
  • Quick set up and execution
  • Efficient tool for UI testing

We add cucumber as dev dependency in the code.

$ npm install --save-dev nightwatch-api nightwatch cucumber chromedriver cucumber-pretty
view raw save_dev.sh hosted with ❤ by GitHub

{
"name": "nightwatchdemo",
"version": "1.0.0",
"description": "To learn automation by nightwatch",
"main": "google.js",
"scripts": {
"test": "nightwatch",
"test:cucumber": "cucumber-js --require cucumber.conf.js --require tests --format node_modules/cucumber-pretty"
},
"author": "",
"license": "ISC",
"dependencies": {
"cucumber": "^5.1.0",
"cucumber-pretty": "^1.5.0"
},
"devDependencies": {
"chromedriver": "^2.40.0",
"nightwatch": "^1.0.19",
"nightwatch-api": "^2.2.0"
}
}
view raw package.json hosted with ❤ by GitHub

Cucumber can be configured in the nightwatch framework to help maintaining the test scenarios in its .feature files. We create a file cucumber.conf.js in the root folder which has the setup of starting, creating and closing webdriver sessions.

const { setDefaultTimeout, AfterAll, BeforeAll } = require('cucumber');
const { createSession, closeSession, startWebDriver, stopWebDriver } = require('nightwatch-api');
setDefaultTimeout(60000);
BeforeAll(async () => {
await startWebDriver();
await createSession();
});
AfterAll(async () => {
await closeSession();
await stopWebDriver();
});

Then we create a feature file which has the test scenarios in Given, When, Then format.  

Feature: Google Search
Scenario: Searching Google
Given I open Google's search page
Then the title is "Google"
And the Google search form exists
view raw google.feature hosted with ❤ by GitHub

For Cucumber to be able to understand and execute the feature file we need to create matching step definitions for every feature step we use in our feature file. Create a step definition file under tests folder called google.js. Step definitions which uses Nightwatch client should return the result of api call as it returns a Promise. For example,

Given(/^I open Google's search page$/, () => {
return client
.url('http://google.com')
.waitForElementVisible('body', 1000);
});
view raw return.sh hosted with ❤ by GitHub

OR

Given(/^I open Google's search page$/, async () => {
await client
.url('http://google.com')
.waitForElementVisible('body', 1000);
});
view raw await_client hosted with ❤ by GitHub

const { client } = require('nightwatch-api');
const { Given, Then, When } = require('cucumber');
Given(/^I open Google's search page$/, () => {
return client.url('http://google.com').waitForElementVisible('body', 1000);
});
Then(/^the title is "([^"]*)"$/, title => {
return client.assert.title(title);
});
Then(/^the Google search form exists$/, () => {
return client.assert.visible('input[name="q"]');
});
view raw google.js hosted with ❤ by GitHub

$ npm run e2e-test
view raw npm_run.js hosted with ❤ by GitHub

Executing Individual Feature Files or Scenarios

  • Single feature file

npm run e2e-test -- features/file1.feature

  • Multiple feature files

npm run e2e-test -- features/file1.feature features/file2.feature
view raw npm_feature.js hosted with ❤ by GitHub

  • Scenario by its line number

npm run e2e-test -- features/my_feature.feature:3

  • Feature directory

npm run e2e-test -- features/dir

  • Scenario by its name matching a regular expression

npm run e2e-test -- --name "topic 1"
view raw npm_topic.sh hosted with ❤ by GitHub

Feature and Scenario Tags

Cucumber allows to add tags to features or scenarios and we can selectively run a scenario using those tags. The tags can be used with conditional operators also, depending on the requirement.  

  • Single tag

# google.feature
@google
Feature: Google Search
@search
Scenario: Searching Google
Given I open Google's search page
Then the title is "Google"
And the Google search form exists
view raw search.sh hosted with ❤ by GitHub

npm run e2e-test -- --tags @google
view raw npm_run_test.sh hosted with ❤ by GitHub

  • Multiple tags

npm run e2e-test -- --tags "@google or @duckduckgo"
npm run e2e-test -- --tags "(@google or @duckduckgo) and @search"

  • To skip tags

npm run e2e-test -- --tags "not @google"
npm run e2e-test -- --tags "not(@google or @duckduckgo)"
view raw skip_tags.sh hosted with ❤ by GitHub

Custom Reporters in Nightwatch and Cucumber Framework

Reporting is again an advantage provided by Cucumber which generates a report of test results at the end of the execution and it provides an immediate visual clue of a possible problem and will simplify the debugging process. HTML reports are best suited and easy to understand due to its format. To generate the same, we will add cucumber-html-reporter as a dependency in our nightwatch.conf.js file.

$ npm install --save-dev cucumber-html-reporter mkdirp
view raw npm_save_dev.sh hosted with ❤ by GitHub

Cucumber-html-reporter in node_modules manages the creation of reports and generates in the output location after the test execution. Screenshot feature can enabled by adding the below code snippet in nightwatch.conf.js

module.exports = {
test_settings: {
default: {
screenshots: {
enabled: true,
path: 'screenshots'
} }  } };
view raw test_setting.sh hosted with ❤ by GitHub

The Cucumber configuration file can be extended with the handling of screenshots and attaching them to the report. Now - It also enables generating HTML test report at the end of the execution. It is generated based on Cucumber built-can be configured here in JSON report using different templates. We use a setTimeout() block in our cucumber.conf.js to run the generation after Cucumber finishes with the creation of json report.

const fs = require('fs');
const path = require('path');
const { setDefaultTimeout, After, AfterAll, BeforeAll } = require('cucumber');
const { createSession, closeSession, startWebDriver, stopWebDriver } = require('nightwatch-api');
const reporter = require('cucumber-html-reporter');
const attachedScreenshots = getScreenshots();
function getScreenshots() {
try {
const folder = path.resolve(__dirname, 'screenshots');
const screenshots = fs.readdirSync(folder).map(file => path.resolve(folder, file));
return screenshots;
} catch (err) {
return [];
}
}
setDefaultTimeout(60000);
BeforeAll(async () => {
await startWebDriver({ env: process.env.NIGHTWATCH_ENV || 'chromeHeadless' });
await createSession();
});
AfterAll(async () => {
await closeSession();
await stopWebDriver();
setTimeout(() => {
reporter.generate({
theme: 'bootstrap',
jsonFile: 'report/cucumber_report.json',
output: 'report/cucumber_report.html',
reportSuiteAsScenarios: true,
launchReport: true,
metadata: {
'App Version': '0.3.2',
'Test Environment': 'POC'
}
});
}, 0);
});
After(function() {
return Promise.all(
getScreenshots()
.filter(file => !attachedScreenshots.includes(file))
.map(file => {
attachedScreenshots.push(file);
return this.attach(fs.readFileSync(file), 'image/png');
})
);
});

In package.json file, we have added the JSON formatter to create a JSON report and it is used by cucumber-html-reporter for the same. We use mkdirp to make sure report folder exists before running the test.

"scripts": {
"e2e-test": "mkdirp report && cucumber-js --require cucumber.conf.js --require step-definitions --format node_modules/cucumber-pretty --format json:report/cucumber_report.json"
}
view raw mkdrip.sh hosted with ❤ by GitHub

After adding this, run the command again

npm run e2e-test
view raw run_test.sh hosted with ❤ by GitHub

When the test run completes, the HTML report is displayed in a new browser tab in the format given below

Test HTML Report

Conclusion

Nightwatch-Cucumber is a great module for linking the accessibility of Cucumber.js with the robust testing framework of Nightwatch.js. Together they can not only provide easily readable documentation of test suite, but also highly configurable automated user tests, all while keeping everything in JavaScript.

Get the latest engineering blogs delivered straight to your inbox.
No spam. Only expert insights.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings

Automation Testing with Nightwatch JS and Cucumber: Everything You Need to Know

What is Nightwatch JS?

Nightwatch.js is a test automation framework on web applications, developed in Node.js which uses W3C WebDriver API (formerly Selenium WebDriver). It is a complete End-to-End testing solution which aims to simplify writing automated tests and setting up Continuous Integration. Nightwatch works by communicating over a restful HTTP API with a WebDriver server (such as ChromeDriver or Selenium Server). The latest version available in market is 1.0.

Nightwatch.Js

Why Use Nightwatch JS Over Any Other Automation Tool?

Selenium is demanded for developing automation framework since it supports various programming languages, provides cross-browser testing and also used in both web application and mobile application testing.

But Nightwatch, built on Node.js, exclusively uses JavaScript as the programming language for end-to-end testing which has the listed advantages -

  • Lightweight framework
  • Robust configuration
  • Integrates with cloud servers like SauceLabs and Browserstack for web and mobile testing with JavaScript, Appium
  • Allows configuration with Cucumber to build a strong BDD (Behaviour Driven Development) setup
  • High performance of the automation execution
  • Improves test structuring
  • Minimum usage and less Maintenance of code

Installation and Configuration of Nightwatch Framework

For configuring Nightwatch framework, all needed are the following in your system -

  • Download latest Node.js
  • Install npm

$ npm install
view raw install.sh hosted with ❤ by GitHub

  • Package.json file for the test settings and dependencies

$ npm init
view raw npm.sh hosted with ❤ by GitHub

  • Install nightwatch and save as dev dependency

$ npm install nightwatch --save-dev
view raw nightwatch_sh hosted with ❤ by GitHub

  • Install chromedriver/geckodriver and save as dev dependency for running the execution on the required browser

$ npm install chromedriver --save-dev

{
"name": "demotest",
"version": "1.0.0",
"description": "Demo Practice",
"main": "index.js",
"scripts": {
"test": "nightwatch"
},
"author": "",
"license": "ISC",
"devDependencies": {
"chromedriver": "^74.0.0",
"nightwatch": "^1.0.19"
}
}
view raw package.json hosted with ❤ by GitHub

  • Create a nightwatch.conf.js for webdriver and test settings with nightwatch

const chromedriver = require('chromedriver');
module.exports = {
src_folders : ["tests"], //tests is a folder in workspace which has the step definitions
test_settings: {
default: {
webdriver: {
start_process: true,
server_path: chromedriver.path,
port: 4444,
cli_args: ['--port=4444']
},
desiredCapabilities: {
browserName: 'chrome'
}
}
}
};

Using Nightwatch - Writing and Running Tests

We create a JavaScript file named demo.js for running a test through nightwatch with the command

$ npm test
view raw npm_test.sh hosted with ❤ by GitHub

//demo.js is a JS file under tests folder
module.exports = {
'step one: navigate to google' : function (browser) { //step one
browser
.url('https://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('input[name=btnK]', 1000)
},
'step two: click input' : function (browser) { //step two
browser
.click('input[name=btnK]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end(); //to close the browser session after all the steps
}
view raw demo.js hosted with ❤ by GitHub

This command on running picks the value “nightwatch” from “test” key in package.json file which hits the nightwatch api to trigger the URL in chromedriver.

There can be one or more steps in demo.js(step definition js) file as per requirement or test cases.

Also, it is a good practice to maintain a separate .js file for page objects which consists of the locator strategy and selectors of the UI web elements.

module.exports = {
elements: {
googleInputBox: '//input[@type="text"]',
searchButton: '(//input[@value="Google Search"])[2]',
headingText: `//h3[contains(text(),'Nightwatch.js')]`
}
}
view raw pageObjects.js hosted with ❤ by GitHub

The locator strategy is set to CSS and Xpath to inspect the UI elements.

locateStrategy: async function (selector) { return await selector.startsWith('/') ? 'xpath' : 'css selector'; }

Nightwatch.conf.js file is also updated with the page_objects location.

const chromedriver = require('chromedriver');
module.exports = {
src_folders : ["tests"], //tests is a folder in workspace which has the step definitions
page_objects_path: 'page_objects/', //page_objects folder where selectors are saved
test_settings: {
default: {
webdriver: {
start_process: true,
server_path: chromedriver.path,
port: 4444,
cli_args: ['--port=4444']
},
desiredCapabilities: {
browserName: 'chrome'
}
}
}
};

Nightwatch and Cucumber JS

Cucumber is a tool that supports Behavior Driven Development (BDD) and allows to write tests in simple english language in Given, When, Then format.

  • It is helpful to involve business stakeholders who can't easily read code
  • Cucumber testing focuses on covering the UI scenarios from end-user’s perspective
  • Reuse of code is easily possible
  • Quick set up and execution
  • Efficient tool for UI testing

We add cucumber as dev dependency in the code.

$ npm install --save-dev nightwatch-api nightwatch cucumber chromedriver cucumber-pretty
view raw save_dev.sh hosted with ❤ by GitHub

{
"name": "nightwatchdemo",
"version": "1.0.0",
"description": "To learn automation by nightwatch",
"main": "google.js",
"scripts": {
"test": "nightwatch",
"test:cucumber": "cucumber-js --require cucumber.conf.js --require tests --format node_modules/cucumber-pretty"
},
"author": "",
"license": "ISC",
"dependencies": {
"cucumber": "^5.1.0",
"cucumber-pretty": "^1.5.0"
},
"devDependencies": {
"chromedriver": "^2.40.0",
"nightwatch": "^1.0.19",
"nightwatch-api": "^2.2.0"
}
}
view raw package.json hosted with ❤ by GitHub

Cucumber can be configured in the nightwatch framework to help maintaining the test scenarios in its .feature files. We create a file cucumber.conf.js in the root folder which has the setup of starting, creating and closing webdriver sessions.

const { setDefaultTimeout, AfterAll, BeforeAll } = require('cucumber');
const { createSession, closeSession, startWebDriver, stopWebDriver } = require('nightwatch-api');
setDefaultTimeout(60000);
BeforeAll(async () => {
await startWebDriver();
await createSession();
});
AfterAll(async () => {
await closeSession();
await stopWebDriver();
});

Then we create a feature file which has the test scenarios in Given, When, Then format.  

Feature: Google Search
Scenario: Searching Google
Given I open Google's search page
Then the title is "Google"
And the Google search form exists
view raw google.feature hosted with ❤ by GitHub

For Cucumber to be able to understand and execute the feature file we need to create matching step definitions for every feature step we use in our feature file. Create a step definition file under tests folder called google.js. Step definitions which uses Nightwatch client should return the result of api call as it returns a Promise. For example,

Given(/^I open Google's search page$/, () => {
return client
.url('http://google.com')
.waitForElementVisible('body', 1000);
});
view raw return.sh hosted with ❤ by GitHub

OR

Given(/^I open Google's search page$/, async () => {
await client
.url('http://google.com')
.waitForElementVisible('body', 1000);
});
view raw await_client hosted with ❤ by GitHub

const { client } = require('nightwatch-api');
const { Given, Then, When } = require('cucumber');
Given(/^I open Google's search page$/, () => {
return client.url('http://google.com').waitForElementVisible('body', 1000);
});
Then(/^the title is "([^"]*)"$/, title => {
return client.assert.title(title);
});
Then(/^the Google search form exists$/, () => {
return client.assert.visible('input[name="q"]');
});
view raw google.js hosted with ❤ by GitHub

$ npm run e2e-test
view raw npm_run.js hosted with ❤ by GitHub

Executing Individual Feature Files or Scenarios

  • Single feature file

npm run e2e-test -- features/file1.feature

  • Multiple feature files

npm run e2e-test -- features/file1.feature features/file2.feature
view raw npm_feature.js hosted with ❤ by GitHub

  • Scenario by its line number

npm run e2e-test -- features/my_feature.feature:3

  • Feature directory

npm run e2e-test -- features/dir

  • Scenario by its name matching a regular expression

npm run e2e-test -- --name "topic 1"
view raw npm_topic.sh hosted with ❤ by GitHub

Feature and Scenario Tags

Cucumber allows to add tags to features or scenarios and we can selectively run a scenario using those tags. The tags can be used with conditional operators also, depending on the requirement.  

  • Single tag

# google.feature
@google
Feature: Google Search
@search
Scenario: Searching Google
Given I open Google's search page
Then the title is "Google"
And the Google search form exists
view raw search.sh hosted with ❤ by GitHub

npm run e2e-test -- --tags @google
view raw npm_run_test.sh hosted with ❤ by GitHub

  • Multiple tags

npm run e2e-test -- --tags "@google or @duckduckgo"
npm run e2e-test -- --tags "(@google or @duckduckgo) and @search"

  • To skip tags

npm run e2e-test -- --tags "not @google"
npm run e2e-test -- --tags "not(@google or @duckduckgo)"
view raw skip_tags.sh hosted with ❤ by GitHub

Custom Reporters in Nightwatch and Cucumber Framework

Reporting is again an advantage provided by Cucumber which generates a report of test results at the end of the execution and it provides an immediate visual clue of a possible problem and will simplify the debugging process. HTML reports are best suited and easy to understand due to its format. To generate the same, we will add cucumber-html-reporter as a dependency in our nightwatch.conf.js file.

$ npm install --save-dev cucumber-html-reporter mkdirp
view raw npm_save_dev.sh hosted with ❤ by GitHub

Cucumber-html-reporter in node_modules manages the creation of reports and generates in the output location after the test execution. Screenshot feature can enabled by adding the below code snippet in nightwatch.conf.js

module.exports = {
test_settings: {
default: {
screenshots: {
enabled: true,
path: 'screenshots'
} }  } };
view raw test_setting.sh hosted with ❤ by GitHub

The Cucumber configuration file can be extended with the handling of screenshots and attaching them to the report. Now - It also enables generating HTML test report at the end of the execution. It is generated based on Cucumber built-can be configured here in JSON report using different templates. We use a setTimeout() block in our cucumber.conf.js to run the generation after Cucumber finishes with the creation of json report.

const fs = require('fs');
const path = require('path');
const { setDefaultTimeout, After, AfterAll, BeforeAll } = require('cucumber');
const { createSession, closeSession, startWebDriver, stopWebDriver } = require('nightwatch-api');
const reporter = require('cucumber-html-reporter');
const attachedScreenshots = getScreenshots();
function getScreenshots() {
try {
const folder = path.resolve(__dirname, 'screenshots');
const screenshots = fs.readdirSync(folder).map(file => path.resolve(folder, file));
return screenshots;
} catch (err) {
return [];
}
}
setDefaultTimeout(60000);
BeforeAll(async () => {
await startWebDriver({ env: process.env.NIGHTWATCH_ENV || 'chromeHeadless' });
await createSession();
});
AfterAll(async () => {
await closeSession();
await stopWebDriver();
setTimeout(() => {
reporter.generate({
theme: 'bootstrap',
jsonFile: 'report/cucumber_report.json',
output: 'report/cucumber_report.html',
reportSuiteAsScenarios: true,
launchReport: true,
metadata: {
'App Version': '0.3.2',
'Test Environment': 'POC'
}
});
}, 0);
});
After(function() {
return Promise.all(
getScreenshots()
.filter(file => !attachedScreenshots.includes(file))
.map(file => {
attachedScreenshots.push(file);
return this.attach(fs.readFileSync(file), 'image/png');
})
);
});

In package.json file, we have added the JSON formatter to create a JSON report and it is used by cucumber-html-reporter for the same. We use mkdirp to make sure report folder exists before running the test.

"scripts": {
"e2e-test": "mkdirp report && cucumber-js --require cucumber.conf.js --require step-definitions --format node_modules/cucumber-pretty --format json:report/cucumber_report.json"
}
view raw mkdrip.sh hosted with ❤ by GitHub

After adding this, run the command again

npm run e2e-test
view raw run_test.sh hosted with ❤ by GitHub

When the test run completes, the HTML report is displayed in a new browser tab in the format given below

Test HTML Report

Conclusion

Nightwatch-Cucumber is a great module for linking the accessibility of Cucumber.js with the robust testing framework of Nightwatch.js. Together they can not only provide easily readable documentation of test suite, but also highly configurable automated user tests, all while keeping everything in JavaScript.

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings