Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Canonical Web Test in NodeJS

DZone's Guide to

A Canonical Web Test in NodeJS

· DevOps Zone
Free Resource

Download the blueprint that can take a company of any maturity level all the way up to enterprise-scale continuous delivery using a combination of Automic Release Automation, Automic’s 20+ years of business automation experience, and the proven tools and practices the company is already leveraging.

Working with web applications in NodeJS is great. Using the same language and libraries on the client and server simplified the thinking. And NodeJS has fast tests and restart for a super quick edit-verify cycle when you’re coding.

I like to write tests to verify the server-side and client-side logic, but do you know that the whole solution really is working? You can of course test your service manually after deploying, but that becomes tedious. By using Selenium, we can test that the solution works end-to-end.

In this article, I show how to write a Mocha test that:

  1. Starts up the Selenium test runner
  2. Creates a browser client that can access the application (using PhantomJS)
  3. Starts up the server and sends the browser to the server (running in ExpressJS)
  4. Clicks a button in the web page that triggers some JavaScript (written in jQuery in this example)
  5. Verifies that the call to the server returns and displays correct data

This test can be run with a simple command after you check out the code and requires no setup on the developers computer!

describe("web application", function() {
  before(function(done) {
    this.timeout(5000);
    client = startWebDriver(function() {
      startServer(function(url) {
        client.init().url(url, done);
      });
    });
  });

  after(function(done) {
    client.end(done);
  })

  it("clicks menu item", function(done) {
    client.click("#showMore", function(err) {
      client.waitFor("#results div", 1000, function(err) {
        client.getText("#results div", function(err, text) {
          expect(text).to.have.string("Here's more");
          done();
        });
      });
    });
  });
});

This test starts a new server and client for each test. When using this for real, you really want to make sure you only start the server and the web driver once as these are expensive operations.

The test case of “it clicks menu item” has a lot of callbacks. There are versions of webdriver APIs for NodeJS which are based on promises that you may enjoy using more.

Implementation details

The full application can be found on Github. To implement it, I used the following NPM modules:

  • phantomjs
  • selenium-standalone
  • webdriverjs
  • expressjs (of course)
  • mocha and chai (of course)

Starting the server looks like this:

var startServer = function(done) {
  var app = require('../app');
  var server = app.listen(0, function() {
    var port = server.address().port;
    done("http://localhost:" + port + "/", done);
  });
}

And the app.js file looks like this:

var express = require('express');
var app = express();
// set up app routes here
module.exports = app;

I have a server.js file which starts up the express application to run normal (outside the tests).

A simplified version of starting Selenium and WebDriver looks like this:

var startWebDriver = function(done) {
  var selenium = require('selenium-standalone');
  var server = selenium({ stdio: 'pipe' });
  // call done when server is started

  var client = require('webdriverjs').remote({
    desiredCapabilities: {browserName: 'phantomjs'}
  });
  return client;
}

I found that Selenium and PhantomJS has some issues, at least on Windows, so my final code needed a few hacks to work. See the full details at github.

Conclusion

A web end to end integration test in NodeJS requires a little bit of shaking your fist at the heavens to get to work the first time, not in the least due to the need to work around limitations in Selenium and PhantomJS. But once you got it up and running, you can easily test not only that your logic works, but that your whole application works together.

When making these tests, I allowed for a little flexibility as well: By setting environment variables, the same tests can be run with a manually deployed server, so you can use it to verify that your staging server is up and running (for example). And of course, you can replace PhantomJS as a web browser with Firefox or Chrome and see the tests run for real in your browser.

Automate the end-to-end tests of your NodeJS applications!

Download the ‘Practical Blueprint to Continuous Delivery’ to learn how Automic Release Automation can help you begin or continue your company’s digital transformation.

Topics:

Published at DZone with permission of Johannes Brodwall, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}