Unit Testing Self-Invoking JavaScript Functions

When Akanoo started out, we only tested our components run on Java – either written in Scala or using Grails or Groovy – with JUnit, ScalaTest and Spock. By the end of 2015 we also wanted unit tests for our JavaScript tracking library that is integrated in our client’s online shops.

Finding the right test framework

Nobody in our team had experience in testing JavaScript, so I went out looking for JavaScript unit test frameworks. What does one do if one has no clue? Google, of course. The first hit was QUnit developed and used by the jQuery team. I looked into other libraries but decided to give QUnit a shot. The reasons I chose it were:

  • Support by the community (In this case the jQuery community.)
  • Used by some big players (jQuery certainly is a big player.)
  • Easy to use (Check out the cookbook.)
  • Easy to understand for Java-developers (Hence, similarity with JUnit.)
  • Plug-in support & availability of plug-ins (We’ll come to this later.)

So, I had chosen my test framework. Let’s write some tests.

Testing self-invoking JavaScript Functions

Well, testing wasn’t that easy at the beginning. Our tracking script is encapsulated in a self-invoking function also known as immediately-invoked function expression (IIFE). The reason behind is to avoid polluting the global space (everything in the window object) with our functions and variables and only allow access via our API calls using the exposed function at(). See an example of an immediately-invoked function expression below:

As the name says, the function is immediately invoked after definition and I have no chance to call the function itself or to access the variables and functions inside. What could I do to test the function bla() in the above example?
My first idea was to comment out the two lines that define the function as self-invoking and define the parameterized variables by hand:

I am now able to call the function bla() and access the variable foo. So I went over to my test files and wrote some QUnit tests.

Spying with Sinon.js

Once I finished writing some easy test checking for the output of functions with various input parameters. Unfortunately, some functions are called inside other functions and these make for harder testing. If I want to know whether the inner function has been called, I need to spy on its execution.

QUnit itself doesn’t offer functions for spying, so I googled again to find a solution for JavaScript “mocking” [https://en.wikipedia.org/wiki/Mock_object]. I stumbled upon Sinon.js [http://sinonjs.org/] which offers spies, stubs and some more nifty features and integrates nicely with QUnit.

I started to write some tests but the function sinon.spy(object, “function”) requires to specify the encapsulating object of the “function” to spy. After my changes to the self-invoking function expression the functions reside in the “global” scope which in JavaScript means they lie under the window object.

// the following line will be replaced by the code in the comment
var a = window, b = document;//(function(a, b) {
  // our tracking code goes here
  var obj = {
    // variables go here
    foo: "bar";
  }
  
  // functions go like this
  obj.bla = function() {
    // sample function
    console.log(foo);
  }
//})(window, document);

Unfortunately, I wasn’t able to spy functions using Sinon on the window object. So, I went on putting all functions inside my faked IIFE inside an object to make them testable. Of course, I had to refactor the existing code already to some extent, i.e. extracting functions, avoiding anonymous functions etc. I strongly recommend to use JSHint.

Notice: When asserting spies with Sinon’s function withArgs(arg0, arg1, …) be aware that the order of arguments must be the same as in the call. If you want to check for the first two of three arguments, you may omit the third but if you want to check for the latter ones, the first argument needs to be defined.

Stubbing with Sinon.js

Sometimes the result of function A is dependent on the result of function B that is called inside function A. To test, I have to manipulate the inner function B to always return a predefined value. This is called stubbing and can be done with Sinon.js by calling sinon.stub(object, “function”).
You should also check out the faked XHR and faked server that Sinon offers. They were very helpful for my unit tests.

Conclusion

If you’ve read until now you certainly can guess that it was a long way down the road to 95% test coverage (measured with JSCover). The upsides of this solution using QUnit and Sinon.js is apparently that we achieved the possibility of unit testing. The obvious downside is the superfluous object in the IIFE. That is, however, not so bad as the Google closure compiler with hard optimization enabled minifies the code efficiently.

Check out the second part of the JavaScript Testing Series: How to run JavaScript QUnit Tests upon Deployment using Jenkins & PhantomJS

Published by

Bendix Sältz

Bendix Sältz works as a JavaScript developer on our tracking library, leads the team to do the technical integrations of our tracking tag into our customer's online shops and is project manager for the dashboards we offer our clients to analyse their performance. For questions you can reach out in the comments below.