Using with Cucumber
Getting Started
Before diving in technical steps we highly recommend to check out the Cucumber introduction page. If you like video tutorials we recommend checking out tutorial created by Domenico Gemoli
Step 1 - Installing dependencies
Let's start with installing all the dependencies. First we need to have Nightwatch.js and Cucumber.js to be installed locally. If you are new to Nightwatch.js you can read the developer guide. Also we need some browser WebDriver. In this example we are going to test using Google Chrome browser. So we are installing the ChromeDriver. We use cucumber-pretty
to make the output more verbose.
$ npm install --save-dev nightwatch-api nightwatch cucumber chromedriver cucumber-pretty
Step 2- Configuring Nightwatch.js
Nightwatch.js requires a configuration to be able to start the correct WebDriver with the needed parameters. Create a JavaScript configuration file in the project root folder. We use nightwatch.conf.js
instead of nightwatch.json
for more flexibility. In the configuration file we provide the port we are going to use, set the browser name to "Chrome" and provide path for installed ChromeDriver. We don't need to specify src_folders
as test are running using Cucumber. Check out Nightwatch docs where all options are documented. Please note that not all of them are supported here.
const chromedriver = require('chromedriver');
module.exports = {
test_settings: {
default: {
webdriver: {
start_process: true,
server_path: chromedriver.path,
port: 4444,
cli_args: ['--port=4444']
},
desiredCapabilities: {
browserName: 'chrome'
}
}
}
};
Step 3 - Configuring Cucumber
Cucumber also needs some configuration. Create a JavaScript configuration file called cucumber.conf.js
in the project root folder. This file is responsible for setting up the default timeout, starting the WebDriver and creating the session.
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();
});
Step 4 - Writing a feature file
Let's create our first feature file under features
folder called google.feature
.
Feature: Google Search
Scenario: Searching Google
Given I open Google's search page
Then the title is "Google"
And the Google search form exists
Step 5 - Writing step definitions
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 step-definitions
folder called google.js
.
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"]');
});
Step 6 - Creating npm script
For convenience we are creating an npm script in our package.json
to be able to execute the test with a short command. You can choose any name for it.
{
...
"scripts": {
"e2e-test": "cucumber-js --require cucumber.conf.js --require step-definitions --format node_modules/cucumber-pretty",
...
}
...
}
Step 7 - Run the tests
We are ready to run our first test.
$ npm run e2e-test
> nightwatch-api-test@1.0.0 e2e-test /home/igor/test/nightwatch-api-test
> cucumber-js --require cucumber.conf.js --require step-definitions --format node_modules/cucumber-pretty
Feature: Google Search
Scenario: Searching Google
Given I open Google's search page
√ Element <body> was visible after 96 milliseconds.
Then the title is "Google"
√ Testing if the page title equals "Google" - 18 ms.
And the Google search form exists
√ Testing if element <input[name="q"]> is visible - 98 ms.
1 scenario (1 passed)
3 steps (3 passed)
0m02.263s
For more examples check out the the cucumber-example or cucumber-selenium-example projects.
Executing individual feature files or scenarios
Single feature file
npm run e2e-test -- features/google-search.feature
Multiple feature files
npm run e2e-test -- features/google-search.feature features/duckduckgo-search.feature
Glob pattern
npm run e2e-test -- features/**/*.feature
Feature directory
npm run e2e-test -- features/dir
Scenario by its line number
npm run e2e-test -- features/my_feature.feature:3
Scenario by its name matching a regular expression
npm run e2e-test -- --name "topic 1"
Feature and Scenario Tags
You can selectively run features and scenarios based on tags. More details
# 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
npm run e2e-test -- --tags @google
or for multiple tags
npm run e2e-test -- --tags "@google or @duckduckgo"
npm run e2e-test -- --tags "(@google or @duckduckgo) and @search"
You can also skip features or scenarios based on tags
npm run e2e-test -- --tags "not @google"
npm run e2e-test -- --tags "not(@google or @duckduckgo)"
Custom Reporters
You can provide multiple reporters (formatters) for Cucumber. To generate an HTML view of your test reports, you can use cucumber-html-reporter.
Step 1 - Installing dependencies
$ npm install --save-dev cucumber-html-reporter mkdirp
Step 2 - Configuring Nightwatch.js
HTML reports can contain screenshot images about the tested application in the state of feature step failure. This is a very handy feature as it provides immediate visual clue of possible problem and will simplify the debugging process. You can enable it in Nightwatch configuration file.
module.exports = {
test_settings: {
default: {
screenshots: {
enabled: true,
path: 'screenshots'
}
// ...
}
// ...
}
};
Step 2 - Create a cucumber config file
We also need to extend the Cucumber configuration file with handling of screenshots and attaching them to the report. Also the html report generation can be configured here. This report is generated based on Cucumber builtin json report using different templates. We use a setTimeout as we want to run the generation after Cucumber finishes with the creation of json report. Unfortunately currently there is no separate hook in Cucumber for doing this.
const fs = require('fs');
const path = require('path');
const { setDefaultTimeout, After, AfterAll, BeforeAll } = require('cucumber');
const {
createSession,
closeSession,
startWebDriver,
stopWebDriver,
getNewScreenshots
} = require('nightwatch-api');
const reporter = require('cucumber-html-reporter');
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'
}
});
}, 1000);
});
After(function() {
getNewScreenshots().forEach(file => this.attach(fs.readFileSync(file), 'image/png'));
});
For details on available options for report generation, see the Cucumber HTML Reporter documentation.
Step 3 - Update your npm scripts
{
...
"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",
...
}
...
}
Notice we have added the json
formatter. This generates a JSON
report which is used by cucumber-html-reporter
to generate the HTML report.
We use mkdirp
to make sure report
folder exists before running the test.
Step 4 - Run the tests
$ npm run e2e-test
When the test run completes, the HTML report is displayed in a new browser tab.
Example reports are available in the Cucumber HTML Reporter documentation.
For working example check out the cucumber-example in the repository.