Nightwatch
Info Installation of an example isn't necessary. Should you desire, an example can be had in a GitHub Kanban Repository. It is a simple ReactJS web app with a configuration to run a Nightwatch driven Selenium acceptance test. If you want to run the test locally, see Clone and Run Example Project.
Nightwatch is a pure-JavaScript Selenium client. Nightwatch communicates with a Selenium server using the W3C WebDriver Standard1. The developer writes JavaScript tests using a Behavioral-Driven Development API exposed by Nightwatch.
Simple Test Examples
The following code snippet shows how a developer would start and end a test case on a web page.
var kanban;
module.exports = {
before: function (client) {
console.log('Open browser...');
kaban = client
.url('http://gkedge.github.io/Kanban/')
.waitForElementVisible('body', 250);
},
after: function (client) {
console.log('Closing down...');
client.end();
},
...
}
Line 5-7 waits until the Selenium server detects the <body/
> tag in the browser on page-load. Future tests will reference the saved, opened session.
The following code snippet shows two tests on the opened session:
var kanban;
module.exports = {
before: function (client) {
console.log('Open browser...');
// A 'page' assumes a single URL is provided
// to navigate to.
kanban = client.page.kanbanPage().navigate();
},
after: function (client) {
console.log('Closing down...');
client.end();
},
'Finding title': function () {
kanban.assert.title('Kanban app');
},
'Adding Kanban Lane': function () {
kanban.click('@addLaneBtn');
kanban.waitForElementVisible('@laneOne', 100);
}
};
- The "Finding title" test searches for the title tag on page-load.
- The "Adding Kanban Lane" test clicks the 'add-lane' button and detects if the newly added lane appears.
Notice that when the test interacts with a DOM element, it finds it using CSS syntax. See lines 6 & 7 in beforeAfter.js
snippet and lines 8 & 9 in the simpleTest.js
snippet. This syntax is familiar and natural to web developers. Though CSS has the advantage of being a familiar DOM search syntax, those CSS strings will change over the course of a project. Tests could reference DOM elements many times. Riddling a test suite with copies of the same brittle CSS strings isn't DRY. IOWs: lots of maintenance. Enter PageObject
's.
Nightwatch PageObject
PageObject
's are a general acceptance testing abstraction. They captures element identifiers into a single object. If an element identifier changes, a single place within it's related PageObject
needs maintenance. The test suite stays intact. The 'Page' part of the PageObject
name is important. Minimally, each page should have a dedicated PageObject
to further ease maintenance. A web page could get sufficiently complex to warrant more than one PageObject
; perhaps a PageObject
per panel.
The following PageObject
abstracts the CSS identifiers for the Kanban page:
module.exports = {
url : 'http://localhost:8888',
elements: {
page : 'body',
addLaneBtn: 'button.add-lane',
laneOne: 'div.lane[data-lane-num="0"]'
}
};
kanbanPage
captures the 4 CSS identifiers used in our test suite snippets above. Nightwatch's testing API provides fluent sugar to ease access to the PageObject
. That sugar makes the name of the PageObject
file significant. Here are the tests rewritten using the fluent page API and less brittle element identifiers. Line 7 requires PageObject
file named kanbanPage.js
:
var kanban;
module.exports = {
before: function (client) {
console.log('Open browser...');
// A 'page' assumes a single URL is provided
// to navigate to.
kanban = client.page.kanbanPage().navigate();
},
after: function (client) {
console.log('Closing down...');
client.end();
},
'Finding title': function () {
kanban.assert.title('Kanban app');
},
'Adding Kanban Lane': function () {
kanban.click('@addLaneBtn');
kanban.waitForElementVisible('@laneOne', 100);
}
};
Easy Peasy
These tests are not hard to write. See Complete Test for the complete Kanban web application acceptance test suite. See KanbanPage for the Kanban PageObject
.
1. The W3C standard was formerly known as the JSON Wire Protocol ↩