E2E Testing with Nightwatch and Nuxt

The Nuxt team provides some great documentation on getting started with e2e testing using Ava . But if you’re looking for a little more power, Nightwatch is worth a try.

Getting Started

I’m going to skip over the installation details and assume that we’re working on a project that contains the latest version of Nightwatch and an appropriate webdriver, like Chrome .

Basic Configuration

In the root directory of your project, Nightwatch will look for nightwatch.json or nightwatch.conf.js. In my example, I used a single nightwatch.json file to configure my webdriver. (I’m using Chrome in this instance.)

The nightwatch docs do a good job of explaining most of these settings, so I’ll just highlight a couple that are relevant to our task.

nightwatch.json

{
    "src_folders": [
        "tests"
    ],
    "exclude": [
        "tests/globals.js"
    ],
    "webdriver": {
        "start_process": true,
        "server_path": "node_modules/.bin/chromedriver",
        "cli_args": [
            "--verbose"
        ],
        "port": 9515
    },
    "test_settings": {
        "default": {
            "desiredCapabilities": {
                "browserName": "chrome"
            },
            "globals": {
                "asyncHookTimeout": 60000
            }
        }
    },
    "globals_path": "tests/globals.js"
}

exclude

I have a global configuration file that I decided to store in the same directory as my tests. I suspect this isn’t considered best practice, but my root directory is already crowded enough. However, by placing this file in the tests directory, nightwatch tries to open the file and run tests. To avoid this, I’ve added the tests/globals.js file to the exclude array.

globals_path

As I mentioned above, I have a file that contains global configuration and hooks for all of my tests. This option lets you instruct nightwatch where to find your global settings and hooks.

globals.asyncHookTimeout

In our before hook, which prepares our environment for testing, I’m building the app and running the server. However, nightwatch was timing out before Nuxt was finished building our app. So I set this value to 60 seconds. This gives our before and after hooks enough time to build and serve our app before moving on to running the tests.

Note: Technically you should be able to set this value in the tests/globals.js that was created, but doing so caused the chromedriver to crash, so I just set the value here instead. 🤷‍♂️

Global Configuration and Hooks

As mentioned above, the global settings and hooks are stored in a javascript module, tests/globals.js. Check out the source code for a complete set of properties .

Note: The example below is using Nuxt 2.8.1. There’s a good chance that the process for programmatically building and serving the app may have changed in recent versions.

tests/globals.js

const resolve = require('path').resolve;
const Nuxt = require('nuxt').Nuxt;
const Builder = require('nuxt').Builder;

/**
 * Nightwatch
 * @url https://nightwatchjs.org/guide/
 */

// Used to store the nuxt server instance
let nuxtInstance = null;

module.exports = {

  // The host for nuxt server
  serverHost: 'localhost',

  // Which port to run nuxt on
  serverPort: 5555,

  before : async function(browser, done) {
    console.log("Starting Nuxt Server")
    const rootDir = resolve(__dirname, '../')
    let config = {}
    try { config = require(resolve(rootDir, 'nuxt.config.js')) } catch (e) {}
    config.rootDir = rootDir // project folder
    const nuxt = new Nuxt(config)
    nuxtInstance = nuxt // We keep a reference to Nuxt so we can close the server at the end of the test
    await new Builder(nuxt).build()
    await nuxt.server.listen(this.serverPort, this.serverHost)
    done();
  },

  after : async function(browser, done) {
    console.log('Shutting Down Nuxt');
    await nuxtInstance.close();
    done();
  },
}

The before method runs before our tests and fires up the Nuxt server to run locally on port 5555.

Once all of the tests are complete, the after method shuts down the Nuxt server instance.

Finally, writing and running the tests:

Just to make sure things were working properly, I created a simple test that loads the app, waits for the body to load, and asserts that the title is correct.

tests/index.test.js

// Needed to get the serverHost and serverPort
const globals = require("./globals");

/**
 * Nightwatch
 * @url Setup Guide https://nightwatchjs.org/guide/
 * @url API Reference https://nightwatchjs.org/api/commands/
 */
module.exports = {

  // Set true to disable this test
  disabled: false,

  'Page: /' : function (browser) {
    browser
      .url(`http://${globals.serverHost}:${globals.serverPort}`)
      .waitForElementVisible('body')
      .assert.titleContains('Name of App')
      .end();
  }
}

I used my globals.js module to determine the host and port of our Nuxt server. The rest of the code is part of the Nightwatch API, which is super-readable.

Running The last step is to add the nightwatch command to our package.json, so that we can easily run the tests with yarn or npm.

package.json

{
  "name": "my-cool-app",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "nuxt build --spa",
    "test": "nightwatch"
  },
  ...
}

Now we can run our tests from the command line:

$ yarn run test