JavaScript
Article

What’s New in QUnit 1.16

By Aurelio De Rosa

Testing is an essential part of the workflow of every developer, or at least it should be. A survey of some years ago showed that about 50% of JavaScript developers don’t write tests at all, which is a little bit scary. A few months ago, I tried to encourage the practice of testing in JavaScript with a 3-parts series about QUnit, a JavaScript unit-testing framework. If you missed it, this series is made of the articles Getting Started with QUnit, How to Test Asynchronous Code with QUnit and QUnit Advanced Concepts: Modules and Configuration.

In December, version 1.16 of this framework was released with some important changes. In this article I’ll introduce you to them, and describe how they can affect your tests.

Preparing for Version 2.0

Updating your tests to version 1.16 now will help you in the process of the migration to version 2.0. QUnit 1.16 introduces several new methods that will become the default in the next milestone, so planning now is a smart way to be prepared for the major release. Besides, as we’ll see in a few moments, in version 1.16 a couple of methods that you have used to test asynchronous code have been deprecated and some properties renamed, so you must be aware of the changes.

New Way to Test Asynchronous Code

Up to version 1.15, to test an asynchronous function you typically used a different method to define the test called QUnit.asyncTest(), and the QUnit.start() and QUnit.stop() methods. For example, let’s say that you had a function called max() that calculates the maximum from a given set of numbers, in QUnit 1.15 you could write a test like the following:

QUnit.asyncTest('max', function (assert) {
   expect(2);
   QUnit.stop(1);

   window.setTimeout(function() {
      assert.strictEqual(max(), -Infinity, 'No parameters');
      QUnit.start();
   }, 0);

   window.setTimeout(function() {
      assert.strictEqual(max(3, 1, 2), 3, 'All positive numbers');
      QUnit.start();
   }, 0);
});

Starting from version 1.16 QUnit.asyncTest(), QUnit.start(), and QUnit.stop() are deprecated. To define an asynchronous test you can use the same QUnit.test() method as you’d do for a synchronous test. The start/stop mechanism has been replaced by a new one that uses a new assertion method called async. The latter returns a unique resolution callback each time is invoked and this callback must be executed within the asynchronous operation in replacement of QUnit.start(). The callback returned from the QUnit.async() method can’t be executed twice because it’ll throw an error, so you don’t have to worry about that.

Rewriting the previous test according to the new mechanism results in the following code:

QUnit.test('max', function (assert) {
   expect(2);

   var done1 = assert.async();
   window.setTimeout(function() {
      assert.strictEqual(max(), -Infinity, 'No parameters');
      done1();
   }, 0);

   var done2 = assert.async();   
   window.setTimeout(function() {
      assert.strictEqual(max(3, 1, 2), 3, 'All positive numbers');
      done2();
   }, 0);
});

You can see the last snippet in action below and its code is also available as a JSFiddle:

Support for Promises

QUnit.test() can now automatically handle the asynchronous resolution of a Promise. Promise are an interesting pattern that has been used a lot in the last few years as a way to replace callbacks and to avoid what is known as the callback hell. Promises have been introduced natively in ECMAScript 6 and browsers are starting implementing this feature. If you need an introduction to promise, you can read the article JavaScript Promises – There and back again.

Returning to the change made in QUnit 1.16, if you return a thenable Promise as the result of your callback function, QUnit will wait for the test to resolve or reject. An example of this new feature, taken from the relevant page of official documentation, is reported below:

QUnit.test( "a Promise-returning test", function( assert ) {
  assert.expect( 0 );
 
  var thenable = new Promise(function( resolve, reject ) {
    setTimeout(function() {
      resolve( "result" );
    }, 500 );
  });
  return thenable;
});

New Method: QUnit.skip()

In addition to the QUnit.async() method, we have QUnit.skip(). It can be used to define tests that you want to temporarily disable and must not be executed. To skip a test you can replace a call to QUnit.test() with QUnit.skip(). So, let’s say that you have the test:

QUnit.test('test', function(assert) {
   // code goes here
});

You can replace the call to QUnit.test() with QUnit.skip() as shown below:

QUnit.skip('test', function(assert) {
   // code goes here
});

This simple change enables you to avoid commenting the entire tests. The skipped test is still displayed in the HTML reporter but is marked as “SKIPPED”.

New Properties to Define Setup and Teardown Functions

QUnit allows to keep our tests organized by splitting the code in multiple modules, which is particularly useful if we’re writing tests for a large project because it enhances its maintainability. To do so, the framework provides a method named QUnit.module() to group tests into modules. This method had a second parameter, referred in the documentation as lifecycle. It’s an object that can contain two optional functions to run before, setup property, and after, teardown property, each test. For example you can define a module as reported below:

QUnit.module('My module, {
   setup: function() {},
   teardown: function() {}
});

In version 1.16 these two properties have been deprecated and replaced by two equivalent properties named beforeEach and afterEach respectively. So, starting from this version you should define a module as:

QUnit.module('My module, {
   beforeEach: function() {},
   afterEach: function() {}
});

This change make sense as the functions are actually ran before and after each test, and not before and after each module as the original names would imply.

Other Changes

QUnit is now compatible with Rhino when ran with the -require option. The framework searches for an exports object and uses that to export itself.

In the article QUnit Advanced Concepts: Modules and Configuration I covered all the options available. In the new version of QUnit, the module property has been renamed in moduleFilter.

When clicking the “Rerun” link for a single test, a hash of the test name is now used to reference the test, called testId, instead of the previous testNumber. This change ensures that even if the order of tests change, QUnit will rerun the same test selected.

Conclusions

In this brief article you’ve learned the new features and changes made in QUnit 1.16. In case you want to discover even more, you can take a look at the changelog. Upgrading your test to this version shouldn’t be very hard but obviously it also depends on the amount of tests your project has.

What do you think of the changes? Are you using QUnit to test your projects? What are your thoughts? Let’s start a discussion.

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.