Overview

Most of the time you will need to extend the Nightwatch commands to suit your own application needs. To do so, create a new folder (e.g. nightwatch/commands) and start defining your own commands inside, each in its own file.

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

nightwatch.json
{
  "custom_commands_path" : "nightwatch/commands"
}

The command name is the name of the file itself.

Define a custom command

There are two main ways in which you can define a custom command:

1) Class-style commands

This is the recommended style of writing custom commands and it's also how most of the Nightwatch's own commands are written. Your command module needs to export a class constructor with a command instance method representing the command function.

All Nightwatch commands are asynchronous which means that custom commands must signal the completion (in the command method). This can be achieved in two ways:

  1. returning a Promise
  2. emitting a "complete" event (in this case the class needs to inherit from Node's EventEmitter)

Returning a Promise is the recommended way. Class-based command methods are run in the context (the value of this) of the class instance. The browser object is available via this.api.

The example below performs the equivalent of the .pause() command. Note the two variations regarding the completion.

The return value

You can also specify a return value, either as the argument with which the Promise will resolve, or as an argument to the "complete" event call.

Completion via a Promise
nightwatch/commands/customPause.js
module.exports = class CustomPause {
  command(ms, cb) {
    // If we don't pass the milliseconds, the client will
    // be suspended indefinitely
    if (!ms) {
      return;
    }
    
const returnValue = { value: 'something' };
return new Promise((resolve) => { setTimeout(() => { // if we have a callback, call it right before the complete event if (cb) { cb.call(this.api); }
resolve(returnValue); }, ms); }); } }

The command method can also be async. In this case, you only need to return a value because async methods return a Promise already.

Here's another example:

nightwatch/commands/customCommand.js
module.exports = class CustomCommand {
  async command() {
    let returnValue;
    try {
      returnValue = await anotherAsyncFunction();
    } catch (err) {
      console.error('An error occurred', err);
      returnValue = {
        status: -1,
        error: err.message
      }
    }
    
return returnValue; } }
Completion via the "complete" event
nightwatch/commands/customPause.js
const Events = require('events');

module.exports = class CustomPause extends Events { command(ms, cb) { // If we don't pass the milliseconds, the client will // be suspended indefinitely if (!ms) { return; }
const returnValue = { value: 'something' };
setTimeout(() => { // if we have a callback, call it right before the complete event if (cb) { cb.call(this.api); }
// This also works: this.complete(returnValue) this.emit('complete', returnValue); }, ms); } }

Using Nightwatch protocol actions

Since v1.4, you can also directly use the protocol actions (via this.transportActions) which Nightwatch uses for its own built-in APIs. These are direct HTTP mappings to Selenium JsonWire or W3C Webdriver protocol endpoints, depending on which one is currently in use.

Here's an example:

nightwatch/commands/customCommand.js
module.exports = class CustomCommand {
  async command() {
    let returnValue;
    
// list all the avaialble transport actions // console.log(this.transportActions);
try { returnValue = await this.transportActions.getCurrentUrl(); } catch (err) { console.error('An error occurred', err); returnValue = { status: -1, error: err.message } }
return returnValue; } }

Directly calling Selenium/Webdriver endpoints

Also, since v1.4 you can (via this.httpRequest(options)) directly call the HTTP endpoints available on the Selenium/Webdriver server from custom commands. This can be a convenient way to extend the provided API protocol, since it is using the same HTTP request interface as for the other protocol actions.

It can be especially useful when using a service which provides additional endpoints, like Appium.

Here's an example:

nightwatch/commands/customCommand.js
module.exports = class CustomCommand {
  async command() {
    let returnValue;
    
try { returnValue = await this.httpRequest({ // the pathname of the endpoint to call path: '/session/:sessionId/url',
// the current Selenium/Webdriver sessionId sessionId: this.api.sessionId,
// host and port are normally not necessary, since it is the current Webdriver hostname/port //host: '', //port: '',
// the body of the request data: { url: 'http://localhost/test_url' },
method: 'POST' }); } catch (err) { console.error('An error occurred', err); returnValue = { status: -1, error: err.message } }
return returnValue; } }

2. Function-style commands

This is a simpler form in which commands can be defined, however they are also quite limited.

The command module needs to export a command function, which needs to call at least one Nightwatch api method (such as .execute()). This is due to a limitation of how the asynchronous queueing system of commands works. You can also wrap everything in a .perform() call. Client commands like execute and perform are available via this.

nightwatch/commands/customCommand.js
module.exports.command = function(file, callback) {
  var self = this;
  var imageData;
  var fs = require('fs');
  
try { var originalData = fs.readFileSync(file); var base64Image = new Buffer(originalData, 'binary').toString('base64'); imageData = 'data:image/jpeg;base64,' + base64Image; } catch (err) { console.log(err); throw "Unable to open file: " + file; }
this.execute(function(data) { // execute application specific code App.resizePicture(data); return true; }, [imageData], // arguments array to be passed function(result) { if (typeof callback === "function") { callback.call(self, result); } });
return this; };

The example above defines a command (e.g. resizePicture.js) which loads an image file as data-URI and calls a method named resizePicture (via .execute()), defined inside the application.

With this command, the test will look something like:

tests/sampleTest.js
module.exports = {
  "testing resize picture" : function (browser) {
    browser
      .url("http://app.host")
      .waitForElementVisible("body")
      .resizePicture("../../../var/www/pics/moon.jpg")
      .assert.element(".container .picture-large")
      .end();
  }
};

Using async/await

You can also use ES6 async/await syntax inside function-style custom commands. Here's another custom command example:

module.exports = {
  command: async function () {
    this.url('http://nightwatchjs.org');
    this.waitForElementVisible('section#index-container');
    
const result = await this.elements('css selector', '#index-container ul.features li'); this.assert.strictEqual(result.value.length, 7, 'Feature elements number is correct'); } };