End-to-End testing in WordPress with Nightwatch.js

End-to-End testing (also called e2e testing) is a really great way to make sure that your plugin or even your entire site is working the way it should.

I’ve written previously about unit testing WordPress plugins which is awesome for checking that the logic of your plugin is working as expected, whereas e2e tests simulate actual user scenarios. You can test how a real user uses your site and that everything is working as it should.

We’re using Nighwatch.js to setup e2e tests for your plugin or application. It’s not the simplest of setups, and the documentation left me scratching my head more than once. This guide will hopefully help you get started without too much pain.

Ok, ok, what do I do already?!

Nightwatch.js uses Selenium which runs a browser that will automatically run your tests. (Don’t worry if it seems a little daunting. Just keep going and it’ll all make sense at the end!).

Selenium runs on Java (yes, yes). If you’re running MacOS you can install Java using brew. If you haven’t got brew installed (why not, it’s amaze?!?!) just yet pop along to https://brew.sh/ to get started and them come back here.

Now run

brew update

followed by

brew cask install java

If you’re running Windows just head on over to https://www.java.com/en/download/help/download_options.xml and come back when you’re done.

We can install Nightwatch.js and the other stuff we need using npm.

Run this in your plugin or theme that needs testing.

npm install nightwatch selenium-server chromedriver --save-dev

or

yarn add nightwatch selenium-server chromedriver --dev

if that’s how you roll. Cool, that’s all our dependencies sorted.

Configuring Nightwatch

Now in the same directory create a file called nightwatch.conf.js and add the following code:

const seleniumServer = require("selenium-server");
const chromedriver = require("chromedriver");

module.exports = {
	"src_folders": [
		"tests/e2e" // Change this to the directory where your test are
	],
	"output_folder": "./reports", // the directory for your rest reports
	"selenium": {
		"start_process": true,
		"server_path": seleniumServer.path,
		"host": "127.0.0.1",
		"port": 4444, // selenium usually runs on 4444
		"cli_args": {
			"webdriver.chrome.driver" : chromedriver.path // There are multiple drivers you can use, eg gecko or IE
		}
	},
	"test_settings": {
		"default": {
			"globals": {
				"waitForConditionTimeout": 5000
			},
			"desiredCapabilities": {
				"browserName": "chrome"
			}
		},
		"chrome": {
			"desiredCapabilities": {
				"browserName": "chrome",
				"javascriptEnabled": true
			}
		}
	}
};

Now in the directory you specified you can write your first test!!

module.exports = {
	'Test Something' (browser) {
		browser
			.url( 'https://wordpress.org/' )
			.waitForElementVisible( '#download' )
			.click( '#download' )
			.waitForElementVisible( '.download-meta' )
			.assert.urlContains( 'download' )
			.end();
	}
};

Run the tests

./node_modules/nightwatch/bin/nightwatch

and be amazed!

Bonus!

Impress your hipster friends by adding the tests to the scripts section of your package.json.

"scripts": {
   "test": "node_modules/nightwatch/bin/nightwatch",
}

Now you can just run

npm test

every time you wish to run your tests.

For documentation on all the assertions you can use just head over to http://nightwatchjs.org/api

Caveats

Nightwatch is generally great, but I ran into occasional issues with clicking on buttons or links outside the browser viewport. It’s unclear to me whether it’s Selenium or Nightwatch that’s to blame here but whatever, it’s annoying!

I got around this by using the following (pretty nasty) workaround.

'Test Complete Order' (browser) {
	browser
		.url( 'http://lavendla.se.dev.synot.io/test/' )
		.waitForElementVisible( '.cart', 5000 )
    		.click( '.go-to-checkout' ) // This didn't work
		.execute(function() { // This DID work!
			document.querySelector('.go-to-checkout').click()
		})
    // ...test something
}