Four Kitchens
Insights

Testing JS code with CasperJS

5 Min. ReadDevelopment

In part one of our CasperJS series, we briefly introduced CasperJS and walked through a functional test for Picturefill, a frontend component of a website. In this article, we will discuss the process of testing your codebase itself. If there are important pieces of JS that allow for critical features on your website, it’s easy to write a CasperJS test that keeps an eye on them for you.

Testing frontend libraries

We rely on many libraries to build websites, and if our code truly depends on one, it’s worth taking some time to verify that it is working properly before testing those components of the site. There are many reasons your libraries could stop working, ranging from developer mistake to aggregation issues in your build process. Because the possibilities are so diverse, it’s a good idea to keep an eye on them using a test.

In our examples we will test a few properties of jQuery and Modernizr, two very common JS libraries. All the techniques shown here can be easily adapted to test custom libraries that you have written, or use within your organization.

Let’s start off by looking at the results of our test so we know what to expect:

The image depicts console output displaying three successful Casper JS tests. The tests report that the version of jQuery is 1.7.1, the version of Modernizr is 2.6.2, and that the Modernizr object contains both expected feature tests: svg and inlinesvg. The test concludes by reporting: PASS 3 tests executed in 3.072 seconds, 3 passed, 0 failed, 0 dubious, 0 skipped.

Testing the version of jQuery or Modernizr

Sometimes code relies on a specific version of jQuery, and although updating it is always the best idea, sometimes it’s just not possible. Often is the case when you use Drupal, which is what this blog is built with. Casper can help you keep an eye on the version.

Since it is written in JavaScript, Casper makes it easy to write JavaScript code that is evaluated in the test session, almost as if we’re typing code into the browser’s JavaScript console. To do this we use a function called assertEvalEquals(). This function does exactly what we want: evaluating the JS we provide in the context of our web page and confirming that the result equals the expected value.

// Check jQuery version
test.assertEvalEquals(function () {
  return jQuery.fn.jquery;
}, '1.7.1', 'jQuery 1.7.1 was found.');

// Check Modernizr version
test.assertEvalEquals(function () {
  return Modernizr._version;
}, '2.6.2', 'Modernizr 2.6.2 was found.');

Here is a brief animated GIF demonstrating how the values we are returning in the above code block are equivalent to typing into the browser’s JS console:

The animated GIF shows how typing the exact strings within our Casper test, jQuery.fn.jquery and Modernizr._version, produce the values that we hardcoded into our test. If these libraries were to be updated, their versions would change and our Casper test would alert us.

Testing the Modernizr object

Another popular JS library is Modernizr. It’s important that Modernizr runs its tests because both CSS and JS can depend on the test results. Since Modernizr’s utility stems from the unique results that each browser gives, a build that includes even a few feature tests can become very complicated to test even with a script. The possibilities increase exponentially with each test, meaning there are 2^N valid configurations of Modernizr for N feature tests.

However, it’s easy to verify if Modernizr is doing its job in the test environment. We do this by checking for a list of expected tests and verifying that each one equals a boolean value. If the test does not equal a boolean, it did not run and we might need to rebuild Modernizr and include the required test.

Here’s an excerpt from the larger Casper test:

test.assertEvalEquals(function () {
  // Which Modernizr tests are required?
  var requiredTests = [
    'inlinesvg',
    'svg'
  ];

  // confirmedTests will only equal `true` if all of the
  // Modernizr object properties are a Boolean value.
  var confirmedTests = requiredTests.map(function(thisTest) {
    retu\r\n \typeof Modernizr[thisTest];
  }).every(function(thisValue) {
    retu\r\n \thisValue === 'boolean';
  });

  // Report result to Casper
  return confirmedTests;
}, true, 'Required Modernizr tests are all present. (inlinesvg, svg)');

So what happened here? First, we assembled a list of properties that we will expect to be booleans (the value of the boolean is irrelevant), and then only return true to Casper if all of the properties return a type of Boolean.

If you’re not familiar with map() and every(), these are vanilla JavaScript methods. map() allows for the execution of a function on every item in an array, returning a new array filled with the results of the function you supply. every() will only return true when all array indices result in true.

In our case, the array of Modernizr properties we specified in advance is processed by asking one question: using typeof, we ask what type of data is this property inside the global Modernizr object? After the new array of types is created, we convert all of these types into a true or false by asking each one if it is a Boolean. If there is a single non-Boolean in the group, every() will report false for the overall test.

In the end, all we send to Casper is a single value: true or false. So Casper can only be as reliable as the code we write for it. No matter what flaws our test code has, it will dutifully report the final value back to us during the test. For that reason, it’s very important to experiment with your test to ensure that you can make it fail. A test is only good if you can confirm that it both succeeds AND fails when you expect it to!

Example script

Here is a gist of the example test, with more detailed inline comments that mirror what we just discussed. feel free to adapt and re-use on your own!

Next up

Hopefully you’re able to use these examples to test your own websites and custom libraries. Check the Fourword each week for a new article about CasperJS. The next article will demonstrate how to simulate user interaction such as clicking, navigating menus, and filling forms within your UI.

Part 3: Simulate user actions with CasperJS