🤯 50% Off! 700+ courses, assessments, and books

QUnit Advanced Concepts: Modules and Configuration

Aurelio De Rosa
Share

In the past weeks I’ve covered several features of QUnit in the tutorials Getting Started with QUnit and How to test asynchronous code in QUnit. I described how to set up the QUnit testing framework to start testing your JavaScript project, what an assert is, what methods QUnit provides, and how to create tests for synchronous or asynchronous code.

In this article I’ll discuss how you can organize your test code in modules, and how you can tweak QUnit to better fit your needs using the configuration properties exposed by the framework.

Organizing QUnit in Modules

The ability to organize a project in smaller, more manageable parts isn’t a new concept in software development. Developers have always strived to keep their code simple and organized by splitting the codebase in multiple files or modules. Testing is no different. Keeping our tests organized and in multiple modules, especially if we’re writing tests for a large project, is very useful and usually enhances its maintainability.

QUnit provides a method named QUnit.module() that allows us to group our tests into modules. The signature of this method is shown below:

QUnit.module(name[, lifecycle])

The name parameter is a string used to identify the module, while lifecycle is an object containing two optional functions to run before (setup) and after (teardown) each test.

To specify which tests belong to a given module, you don’t need to do any sort of wrapping of the tests like this:

// No, it's not like that!
QUnit.module('My first module, {
setup: function() {},
teardown: function() {},
tests: function() {
// Tests here
}
});

A test belongs to a given module simply if it’s defined after a call to QUnit.module() but before another call to QUnit.module() is found. In the next example, we have tests named “Test 1” and “Test 2” that belong to module “Module 1”, and another test, “Test 3”, that belongs to “Module 2”.

// It's like that and that's the way it is
QUnit.module('Module 1');

QUnit.test('Test 1', function(assert) {
// assertions here
});

QUnit.test('Test 2', function(assert) {
// assertions here
})

QUnit.module('Module 2');

QUnit.test('Test 3', function(assert) {
// assertions here
});

Ideally, module names express an isolated part of your project. For example, the jQuery library has the following modules: ajax, core, css, event, selector, etc.

Now that you have a clear idea of how tests are grouped in modules, let’s learn more about the setup and teardown functions. Let’s say that you want to run severals tests on the following object:

var myObj = {
name: 'Aurelio De Rosa',
items: []
};

You want to be sure that before a test is performed, the items property is filled with the numeric values 1, 2 and 3. In addition you want that every time a test is concluded, any additional property that isn’t name or items is deleted from the object. Such a goal can be achieved with the following code:

QUnit.module('My module', {
setup: function() {
myObj.items = [1, 2, 3];
},
teardown: function() {
for (var prop in myObj) {
if (prop !== 'name' && prop !== 'items') {
delete myObj[prop];
}
}
}
});

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

// Set a new property of the myObj object
myObj.color = 'red';

assert.strictEqual(myObj.items.length, 3, 'The setup function has pushed 3 elements');
assert.strictEqual(myObj.items, [1, 2, 3], 'The setup function has pushed the expected elements');
});

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

assert.ok(!myObj.color, 'The teardown function removed the color property');
});

A live demo of this example is shown below and also available as a JSfiddle.

Now, let’s see how we can create a custom configuration in QUnit.

How to Configure QUnit

The QUnit framework exposes a bunch of configuration properties that we can modify to better fit our project’s needs. The framework offers a default configuration good for most cases, but we can tweak it by updating the QUnit.config property. This property is an object containing the following properties (reported in alphabetic order):

  • altertitle: A Boolean to enable (true) or disable (false) QUnit from updating the title of the test page by adding a checkmark or an “x” to specify if a testsuite passed or failed. The default value is true.
  • autostart: A Boolean which, if set to false, specifies that you want to run the tests by yourself by calling QUnit.start() and not when the load event is triggered. The default value is true.
  • hidepassed: A Boolean to specify if the passed tests should be hidden (true) or not (false). The default value is false.
  • module: A string that specifies a single module to run. The default value is undefined, so QUnit runs all the modules defined.
  • reorder: A Boolean to indicate if QUnit should run tests that failed on a previous execution first (true) or not (false). The default value is true.
  • requireExpects: A Boolean to specify if you want to force a call to expect() in each test defined (true) or not (false). The default value is true.
  • testNumber: An array to run specific test blocks by their order number. The order is set as the tests blocks are loaded. The default value is undefined.
  • testTimeout: A number that indicates a maximum time execution after which all tests will fail. The default value is undefined.
  • scrolltop: A Boolean to specify if you want to avoid that QUnits goes to the top of the page when all the tests are executed (true) or not (false). The default value is true.
  • urlConfig: An array that manages the form controls to place into the QUnit toolbar. By extending this array, you can add your own checkboxes and select lists.

Now that you know what features you can modify, let’s see how we can use them. But first, an important point to keep in mind is that the custom configuration must be written after the inclusion of the QUnit’s JavaScript file, but before you define the tests.

Let’s say that you want to force the testers in your team to always define the number of assertions to execute. You also want QUnit to hide the passed tests because the testsuite is very large. Finally, you want to stop QUnit from scrolling to the top of the page automatically. In this case you can write:

<script src="qunit-1.15.0.js"></script>
<script>
QUnit.config.hidepassed = true;
QUnit.config.requireExpects = true;
QUnit.config.scrolltop = true;
</script>
<script>
QUnit.test('My test', function(assert) {
// assertions go here...
});
</script>

In this example we’ve seen a basic custom configuration. You can expand on it and create a very complicated one that is right for your project.

Conclusion

In this article I introduced you to modules in QUnit and showed you how to create a custom configuration. In the first section we discussed how to create a module in QUnit using the QUnit.module() method, and learned how the framework groups tests together. Then, I described how to create setup and a teardown functions that run before and after every test in a module. In the second section, I listed all the properties exposed by QUnit to change its default configuration to better fit your project’s need.

I hope you liked this tutorial. Thanks to this, and my previous articles, you’re now able to start testing your JavaScript-based projects with QUnit.