How to make Nigthwatch.js library work with async/await?

Although it's quite powerful tool, you need to customize it to get the full benefit of it. One of these improvements is usage of async/await commands (from Node 7.6 version). In this article I am going to show you how to adjust your code to make this commands work.

|

Introduction

Nightwatch.js is one of the popular testing frameworks for End-to-end tests in web development. It's written in Node.js and works fine with most popular browsers and devices.

Although it's quite powerful tool, you need to customize it to get the full benefit of it. One of these improvements is usage of async/await commands (from Node 7.6 version). In this article I am going to show you how to adjust your code to make this commands work.

Problem

As most programmers claim await/async commands are currently the easiest and most effective way to handle asynchronous code. I'm not going into much details - but just remind you about famous "callback hell" problem. If you want details, google it.

Actually Nightwatch.js library uses callbacks everywhere. Every command or assertion in it returns promise. It might be a bit difficult to get your head around it at the first time and with time you're looking for other possible ways to handle asynchronicity within this framework.

I'm going to show you what I've come up with.

Simple example

Please note: All examples use nightwatch-cucumber library.

When(/^Load the game$/g, () => {
    client.url("https://my-game-address", function() {
        client.waitForElementToBeVisible(".main-div");
    });
});

What this code means is:

  1. Go to certain URL
  2. Wait for the game to load

These two steps need to be executed one after another. Above implementation can be rewritten to:

When(/^Load the game$/g, async () => {
    await client.url("https://my-game-address");
    await client.waitForElementToBeVisible(".main-div");
});

These two implementations are exactly the same.

The second one is cleaner: instead of two levels of code we have only one plain text, easily readable. It is a common practice within programmers to reduce code complexity. For more detalis refer to Sonar documentation, for instance.

Complex example

But what if we use Nightwatch function to get some information from the website. Nightwatch commands doesn't return such value directly, it is passed only to callback.

When(/^Balance in the game should equal (.+)$/g, (expectedBalance) => {
    client.getBalance(function(result) {
        client.assert.ok(expectedBalance === result.value);
    });
});

What this code means is:

  1. Take user balance from the game
  2. Assert user balance to expected value

And again: these two steps need to be executed one by one. We can refactor this code by adding another variable which will be assigned in the callback. It will look like that:

When(/^Balance in the game should equal (.+)$/g, async (expectedBalance) => {
    const actualBalance = {};

    await client.getBalance(function(result) {
        actualBalance.value = result.value;
    });

    await client.assert.ok(expectedBalance === actualBalance.value);
});

or making the code cleaner:

# callbacks.js

const assignVariable = (variable) => {
    return (result) => {
        variable.value = result.value;
    };
};

module.exports = { assignVariable };

and

# main.js

const { assignVariable } = require("utils/callbacks");

When(/^Balance in the game should equal (.+)$/g, async (expectedBalance) => {
    const actualBalance = {};

    await client.getBalance(assignVariable(actualBalance));
    await client.assert.ok(expectedBalance === actualBalance.value);
});

Warning! Please note that passing parameters by variable in JavaScript is a bit complicated. In function assignVariable you cannot just replace one variable with another. For details refer to this Stackoverflow question.

Summary

This article was about introducing async/await commands into Nightwatch.js framework. It makes the code cleaner and shorter. Instead of the jungle of tangled callbacks we get plane, easily readable code. This one practice made my work with Nightwatch.js much easier and even pleasant. :)

Happy coding everyone.

Sources

  1. Nightwatch.js website: http://nightwatchjs.org/
  2. Nightwatch cucumber documentation: http://mucsi96.github.io/nightwatch-cucumber/

Paweł Proc

Did you like this article?

How to make Nigthwatch.js library work with async/await?