A Beginner’s Guide To Test Automation With Javascript(Nightwatch.js). Part 3.
Tags: javascript, nightwachjs, testing, guide
Published: 2022-06-07 05:58:54

---
canonical_url: https://blog.loadero.com/2021/06/22/a-beginners-guide-to-test-automation-with-javascriptnightwatch-js-part-3/
---
## Callback functions and command queue in Nightwatch.js
Welcome to the “A beginners guide to test automation with Javascript(Nightwatch.js)” blog series part 3! If you have missed out on the previous parts, make sure to read [part 1: Introduction to Nightwatch.js](https://dev.to/loadero/a-beginner-s-guide-to-test-automation-with-javascript-nightwatch-js-part-1-46lh) and [part 2: The most useful Nightwatch.js commands](https://dev.to/loadero/a-beginner-s-guide-to-test-automation-with-javascript-nightwatch-js-part-2-2f1m) in our blog.

In this article we will look at callback functions and command queue in Nightwatch.js, and as always – feel free to skip to any part you are the most interested in.

- [Callbacks](#Callbacks)
- [Command queue](#Command queue)

Code used in this article can be found in Loadero’s public GitHub examples repository [here](https://github.com/loadero/examples/tree/master/javascript/tests/nw_tutorial/part3).

**Prerequisites**

- It is really recommended that you have read [part 1](https://dev.to/loadero/a-beginner-s-guide-to-test-automation-with-javascript-nightwatch-js-part-1-46lh) and [part 2](https://dev.to/loadero/a-beginner-s-guide-to-test-automation-with-javascript-nightwatch-js-part-2-2f1m) of our “Beginner’s guide to test automation with Javascript(Nightwatch.js).”

- Text editor of your choice (in Loadero we prefer [Visual Studio Code](https://code.visualstudio.com/)).

- [Node.js](https://nodejs.org/en/) (the latest version is preferable, in this example `v14.15.0` will be used).

- [Google Chrome](https://www.google.com/chrome/) and [Firefox ](https://www.mozilla.org/en-US/firefox/new/)browsers.

## Callbacks <a name="Callbacks"></a>

**General**

Nightwatch.js is a framework that utilizes the concept of a callback function (or shortly “callback”) heavily. But what is a callback function exactly?

> A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

(From MDN Web Docs)

For example, a callback can be as simple as the following code.

```
const outerFunction = callback => {
    const callbackResult = callback();
    console.log(callbackResult);
};
const callbackFunction = () => {
    return "Callbacks are cool!";
};
outerFunction(callbackFunction); // => "Callbacks are cool!"
```
`outerFunction()` has one parameter defined, namely, `callback`. `callbackFunction` definition is passed as an argument to `outerFunction()` which is then called inside the outer function body. Then the callback’s result is saved and logged in the console.

> Important: Notice that `callbackFunction` is passed as an argument without function call parenthesis, i.e., (). That is done because a function definition is being passed rather the result of the function call.

##Nightwatch.js callbacks

Since Nightwatch.js commands are [chained](https://en.wikipedia.org/wiki/Method_chaining) one after another, they can’t return any value that can be assigned to a variable. To solve this problem, Nightwatch.js offers to utilize the “returned” value in a callback function, where it can be processed. This callback should accept either no arguments if you don’t want to process the returned value or accepts 1 parameter of type `Object`.

Let’s take a closer look at callbacks on `.getText()` Nightwatch.js function (check its documentation [here](https://nightwatchjs.org/api/commands/#getValue)).

![Callback's of `.getText()` function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ekllzr70sp1xhw91pcc.jpg)
To see the contents of the response object, let’s write the following code.

```
module.exports = {
    test: client => {
        client
            .url('http://example.com/')
            .waitForElementVisible('div', 10 * 1000)
            .getText('h1', response => console.log(response));
    }
};
```

```
// Logs out the following object
{
     sessionId: '8f3d666f316e6aa063b6ed70cfeaafff',
     status: 0,
     value: 'Example Domain'
}
```
As you can see in the callback function response object was logged out with its 3 properties:

- `sessionID`- ID of the particular Nightwatch.js session. Generally, it is not that useful but can be helpful when you are running tests locally in a concurrent manner.
- `status`– indicates the status of the request. Simply put: 0 is a successful request and anything else indicates that an error has occurred.
- `value`– returned value of the command, in this case, the text of HTML element is returned. In most cases, you will be interested in this field since it can be used later in the callback. For example, you can assert whether the text matches your expectations or just save it in some variable for future processing.

> Tip: You can name callback function parameter as you like but response or result are used the most often.

Now let’s take a look at what happens if the command fails to execute properly.

```
module.exports = {
    test: client => {
        client
            .url('http://example.com/')
            .waitForElementVisible('div', 10 * 1000)
            .getText('non.existing.element', response => console.log(response));
    }
};
```
```
// Logs out the following object
{
    status: -1,
    value: {
        error: 'An error occurred while running .getText() command on <non.existing.element>: ',
        message: 'An error occurred while running .getText() command on <non.existing.element>: ',
        stack: 'NoSuchElementError: An error occurred while running .getText() command on <non.existing.element>: \n' +
        '    at GetText.noSuchElementError (/Users/loadero/loadero/test/test-scripts/scripts/javascript/node_modules/nightwatch/lib/element/command.js:399:12)\n' +
        '    at Object.errorHandler (/Users/loadero/loadero/test/test-scripts/scripts/javascript/node_modules/nightwatch/lib/api/element-commands/_baseElementCommand.js:42:30)\n' +
        '    at PeriodicPromise.runAction (/Users/loadero/loadero/test/test-scripts/scripts/javascript/node_modules/nightwatch/lib/utils/periodic-promise.js:64:29)\n' +
        '    at processTicksAndRejections (internal/process/task_queues.js:93:5)'
    }
}
```
Oh, that looks differently, doesn’t it? The 'response' object fields look changed, for example, 'sessionID' is not present anymore, so let’s see what fields are present:

- `status`– this field doesn’t have 0 value since this request is not successful anymore.
- `value`– this field now doesn’t have string value as in the previous example but rather a whole object.
- `value.error`– the error that was raised when running the previous command.
- `value.message`– a more detailed explanation for the `value.error`. In this case, they are the same but in different scenarios, this field may host a more detailed explanation.
- `value.stack`– a stacktrace where this error occurred (notice that Nightwatch.js logs specific line and column of the file where the specific error was triggered to help you debug).

Now, when you know what are callbacks and how they are used in Nightwatch.js, let’s look at the command queue!

## Command queue <a name="Command queue"></a>
Now buckle up because this is the most challenging concept of Nightwatch.js to grasp but don’t be scared away by this – after reading this section, you will understand it well! 

Before we get started, let’s take a look at the following example

```
module.exports = {
    test: client => {
        let text;
        client
            .url('https://duckduckgo.com/')
            .perform(() => {
                text = 'first'; // assigns 'first' to text
            })
            .setValue('#search_form_input_homepage', text)
            .getValue('#search_form_input_homepage', ({ value }) => console.log(value))
            .clearValue('#search_form_input_homepage') // clears input field
            .perform(() => client.setValue('#search_form_input_homepage', text))
            .getValue('#search_form_input_homepage', ({ value }) => console.log(value));
        console.log('second');
    }
};
```
And when this script is run, then the following is logged in the console

```
second
undefined
first
```
Some of you may get confused, to say the least, by this point. Why Nightwatch.js doesn’t log values like this as they should be read –  from top to bottom like this?

```
first
first 
second
```
The reason for this behavior is thoroughly explained in [Understanding the Command Queue](https://github.com/nightwatchjs/nightwatch/wiki/Understanding-the-Command-Queue) Nightwatch.js GitHub wiki (it is a long read but it’s worth it). In this section, we will not look in such detail, this is going to be a summary of sorts. By the way, this command queue example can be found in Loadero’s public GitHub examples repository [here](https://github.com/loadero/examples/tree/master/javascript/tests/nw_tutorial/part2).

**TL; DR**
Nightwatch.js firstly schedules commands in the queue, before executing them. All variables used in scheduled commands are set to their initial values.

Javascript is always executed first, before executing scheduled Nightwatch.js commands.

Then the commands are executed and run in a FIFO (first-in, first-out) manner.

If the command has a callback, then the callback is scheduled right after the outer function.

Once the outer function finishes its execution, the callback is called.

**Command queue creation**
Nightwatch.js utilizes the queue concept for executing various functions. Since that is a queue it follows FIFO rule, so the first command you call is run the first, then the second and so on. This is a key point to remember because Nightwatch.js doesn’t execute the functions as they are called, instead it schedules them in a queue (which essentially is the reason why commands are not executed as you would expect them to be run).

Let’s take a look at the following example

```
module.exports = {
    test: client => {
        client
            .url('http://example.com/')
            .click('a');
    }
  };
```
When Nightwatch.js runs the test, it calls `test()` function which then calls each of these 3 commands. Since they are synchronous, each of these commands is added to the queue one after another. This results in the following queue.

```
[
  {command: 'url', args: ['http://example.com/']},
  {command: 'click', args: ['a']}
]

```
Only then Nightwatch.js traverses the queue and calls each command separately.

**Callbacks in the command queue**
Let’s add a callback to `.click()` function and see how it changes the queue.

```
// test with 'click button' test case
module.exports = {
    test: client => {
        client
            .url('http://example.com/')
            .click('a', () => client.pause(5 * 1000))
    }
};
```
Initially, the command queue looks just like before

```
[
  {command: 'url', args: ['http://example.com/']},
  {command: 'click', args: ['a', callback]}
]
```
When Nightwatch.js begins to traverse the queue, it executes `.url()` command, waits for it to finish, only then executes `.click()` with the provided arguments, and then calls the callback. When the callback is called, it is added to the queue right after `.click()` so it can be executed as the next function. This results in the following queue:

```
[
  {command: 'url', args: ['http://example.com/']}, // executed
  {command: 'click', args: [a, callback]}, // executed
  {command: 'pause', args: [5000]}, // <-- just added
]
```

> Important: One of the most important aspects of the Nightwatch.js command queue is that commands are not executed at the moment they are scheduled. But rather commands get scheduled, then JavaScript code is executed and only then Nightwatch.js scheduled commands get executed one-by-one in queue’s order. This is the reason why `console.log('second')` in the example before was executed first and only afterward console logs in Nightwatch commands.

## Variable resolution in the queue
When it comes to variables in Nightwatch.js, you always have to take into consideration the command queue. If you don’t, then variables might have uninitialized values or just have them incorrectly set.

**Initial variable values**
Take a look at the following code snippet from the already mentioned example.

```
module.exports = {
    test: client => {
        let text;
        client
            .url('https://duckduckgo.com/')
            .perform(() => {
                text = 'first'; // assigns 'first' to text
            })
            .setValue('#search_form_input_homepage', text)
            .getValue('#search_form_input_homepage', ({ value }) => console.log(value))
        // ...
    }
};
```
In this example, `console.log(value)` logs `undefined`. The reason for this is simply that when Nightwatch.js commands queued, their arguments are assigned with the values of that moment. In this case, JavaScript assigns `undefined` to `text` because the variable is not initialized (only declared) and, when `.setValue()` is called, Nightwatch.js uses initial `text` value instead of the one assigned in the `.perform()` callback.

**Variables inside callbacks**
Now, let’s take a look at why variables inside callbacks have proper values, like in this example.

```
module.exports = {
    test: client => {
        let text;
        client
            .url('https://duckduckgo.com/')
            .perform(() => {
                text = 'first'; // assigns 'first' to text
            })            
            .perform(() => client.setValue('#search_form_input_homepage', text))
            .getValue('#search_form_input_homepage', ({ value }) => console.log(value));
        // ...
    }
};
```
Here `console.log(value)` logs out `'first'`. The reason for such behavior is that when Nightwatch.js adds callbacks to the queue, it adds them with values of that current moment, so when they are executed, they have “the latest” values. In this case, when `.perform()` callback is added to the queue, it has text with a value of `'first'`.

**The magic of `.perform()`**
At the beginning of this blog post, it was mentioned that `.perform()` with no parameters is mainly used for dealing with command queue execution order. The reason for that is simply because it allows wrapping some other functions inside a callback, hence making them use the latest variable values. Like so

```
client.perform(() => client.setValue('#search_form_input_homepage', text));
```

> Tip: It is really recommended to use arrow functions for callbacks, mainly because of their conciseness. The recommended code style will be looked at in more detail in the next part of this series.

Another important reason why `.perform()` is often used, is to get rid of the [callback hell](https://devrant.com/rants/1879577/callback-hell) where inside a callback you have a callback that has a callback inside that…, like this

```
module.exports = {
    test: client => {
        let text, text2, text3; // ...
        client.getValue('#input', response => {
            text = response.value;
            client.getValue('#' + text, response => {
                text2 = response.value;
                client.getValue('#' + text2, response => {
                    text3 = response.value;
                    client.getValue('#' + text3, response => {
                        // ...
                    });
                });
            });
        });
    }
};

```
To avoid such situations, wrap these functions inside multiple `.perform()` calls, like this to make your code easier to follow and increase its readability.

```
module.exports = {
    test: client => {
        let text, text2, text3; // ...
        client
            .getValue('#input', response => {
                text = response.value;
            })
            .perform(() =>
                client.getValue('#' + text, response => {
                    text2 = response.value;
                })
            )
            .perform(() =>
                client.getValue('#' + text2, response => {
                    text3 = response.value;
                })
            )
            
            // ...
    }
};
```

## **Summary**
Today you’ve learned what is a callback and how to handle Nightwatch.js responses inside the callback itself. You also learned the challenging Nightwatch.js command queue and its unusual execution order of commands. If you read previous parts of these series, you should be able to create quite [complex test scripts and run them](https://app.loadero.com/signup) locally testing or launching them at a scale in [Loadero](https://loadero.com/).

See you in the next and final part of “A beginner’s guide to test automation with Javascript(Nightwatch.js)” series that will contain some of the best practices used by our engineers to write better scripts, so don’t miss it. Hope this helps you. Thank you for reading, and let's test together!