QUnit.module()
version added: 1.0.0.
Description
QUnit.module( name )
QUnit.module( name, scope )
QUnit.module( name, options )
QUnit.module( name, options, scope )
Group related tests under a common label.
parameter | description |
---|---|
name (string) |
Label for this group of tests. |
options (object) |
Set hook callbacks. |
scope (function) |
A scope for tests, nested modules, and/or hooks. |
All tests inside a module will be grouped under that module. Tests can be added to a module using the QUnit.test
method. Modules help organize, select, and filter tests to run.
Modules may be nested inside the scope of another module. Test results are prefixed with the names of any parent modules. E.g. “Grandparent > Parent > Child > my test”.
QUnit.module.only( name, … )
QUnit.module.skip( name, … )
QUnit.module.todo( name, … )
QUnit.module.if( name, condition, … )
These methods are aliases for QUnit.module()
that apply the behaviour of QUnit.test.only()
, QUnit.test.skip()
, QUnit.test.todo()
, or QUnit.test.if()
to all a module’s tests at once.
Organizing your tests
By default, if QUnit.module
is called without a scope
callback, all subsequently defined tests are automatically grouped into that module, until the next module is defined.
QUnit.module('Group A');
QUnit.test('foo', function (assert) {
assert.true(true);
});
QUnit.test('bar', function (assert) {
assert.true(true);
});
QUnit.module('Group B');
QUnit.test('baz', function (assert) {
assert.true(true);
});
QUnit.test('quux', function (assert) {
assert.true(true);
});
Module scope
The module scope can be used to group tests under a common label. These can be nested to create child modules under a common parent. The module scope can add hooks by calling methods on the hooks
parameter.
parameter | description |
---|---|
hooks (object) |
An object for adding hooks. |
Example:
// Fruit > Berries > cowberry.
// Fruit > Berries > cranberry.
// Fruit > Melons > galia.
// Bread > bake.
// Bread > toast.
QUnit.module('Fruit', function (hooks) {
QUnit.module('Berries', function (hooks) {
QUnit.test('cowberry', function (assert) {
assert.true(true);
});
QUnit.test('cranberry', function (assert) {
assert.true(true);
});
});
QUnit.module('Melons', function (hooks) {
QUnit.test('galia', function (assert) {
assert.true(true);
});
// ...
});
});
QUnit.module('Bread', function (hooks) {
QUnit.test('bake', function (assert) {
assert.true(true);
});
QUnit.test('toast', function (assert) {
assert.true(true);
});
});
Hooks
You can use hooks to run shared code for every test in a module. Add hooks via the hooks
parameter in the module scope (as demonstrated below), or via the options parameter.
Instead of preparing the same fixture code in every test, you can de-duplicate these steps by performing your setup steps in a beforeEach()
hook instead.
QUnit.module('example', function (hooks) {
hooks.before(function () {
// once for all tests
});
hooks.beforeEach(function () {
// before every test
});
hooks.afterEach(function () {
// after every test
});
hooks.after(function () {
// once after all tests are done
});
// define tests here...
});
To apply a hook globally to all modules in a project, use QUnit.hooks
.
Learn about execution order in the Test lifecycle
Hook callback
parameter | description |
---|---|
assert (object) |
An Assert object. |
Each hook for a given QUnit.test, has access to the same assert
object, and the same this
test context, as the test function.
A hook callback may be an async function, or return a Promise or other then-able. QUnit will automatically wait for your hook’s asynchronous work to finish before continuing to execute the tests.
QUnit.module('Database connection', function (hooks) {
hooks.before(async function () {
await MyDb.connect();
});
hooks.after(async function () {
await MyDb.disconnect();
});
// define tests...
});
See Test lifecycle § Async hook callback for how to return a Promise without modern async-await syntax.
It is discouraged to dynamically create a QUnit.test from inside a hook. In order to satisfy the requirement for the after
hook to only run once and to be the last hook in a module, QUnit may associate dynamically defined tests with the parent module instead, or as global test. It is recommended to define any dynamic tests via QUnit.begin()
instead.
Options parameter
You can set the following options to add hooks.
name | description |
---|---|
before (function) |
Runs before the first test. |
beforeEach (function) |
Runs before each test. |
afterEach (function) |
Runs after each test. |
after (function) |
Runs after the last test. |
Any other properties on the options
object are copied into the base test context for the module, which each test inherits from. See also Test lifecycle § Example: Set context via options.
QUnit.module('example', {
before () {
// once for all tests
},
beforeEach () {
// before every test
},
afterEach () {
// after every test
},
after () {
// once after all tests are done
}
});
Changelog
QUnit 2.22 | Added QUnit.module.if() alias. |
QUnit 2.4 | Added QUnit.module.only() , QUnit.module.skip() , and QUnit.module.todo() aliases. |
QUnit 2.0 | Added before and after options.The deprecated setup and teardown options were removed. |
QUnit 1.20 | Introduce scope feature. |
QUnit 1.16 | Added beforeEach and afterEach options.The setup and teardown options were deprecated in QUnit 1.16 and removed in QUnit 2.0. |
Examples
Example: Hooks
QUnit.module('Machine Maker', function (hooks) {
let parts;
hooks.beforeEach(function () {
parts = ['A', 'B'];
});
QUnit.test('make alphabet', function (assert) {
parts.push('C');
assert.equal(parts.join(''), 'ABC');
});
QUnit.test('make music', function (assert) {
parts.push('B', 'A');
assert.equal(parts.join(''), 'ABBA');
});
});
Example: Skip a module
Use QUnit.module.skip()
to treat an entire module’s tests as if they used QUnit.test.skip
. For example, if a module is failing due to a known but unsolved problem.
QUnit.module.skip('Robot', (hooks) => {
let android;
hooks.beforeEach(() => {
android = new Robot();
});
QUnit.test('hello', function (assert) {
assert.strictEqual(android.hello(), 'Hello, my name is AN-2178!');
});
});
Use QUnit.module.if()
, to conditionally skip an entire module. For example, if these tests are only meant to run in certain environments, operating systems, or when certain optional dependencies are installed.
QUnit.module.if('MyApp', typeof document !== 'undefined', (hooks) => {
QUnit.test('render', function (assert) {
assert.strictEqual(MyApp.render(), '<p>Hello world!</p>');
});
});
During development you can programatically focus QUnit to only run tests that you’re currently working on, by changing a call to QUnit.module.only()
. This treats an entire module as if their tests are defined via QUnit.test.only
.
QUnit.module.only('Robot', (hooks) => {
let android;
hooks.beforeEach(() => {
android = new Robot();
});
QUnit.test('hello', function (assert) {
assert.strictEqual(android.hello(), 'Hello, my name is AN-2178!');
});
});
Use QUnit.module.todo()
to mark a feature that is still under development, and is known to not yet be passing all its tests. This treats an entire module’s tests as if they used QUnit.test.todo
.
QUnit.module.todo('Robot', (hooks) => {
let android;
hooks.beforeEach(() => {
android = new Robot();
});
QUnit.test('hello', function (assert) {
assert.strictEqual(android.hello(), 'Hello');
// TODO
// Actual: Goodbye
// Expected: Hello
});
});
Error: Cannot add hook outside the containing module
If you encounter this error, it means you have called hooks.beforeEach()
or hooks.afterEach()
on the “hooks” parameter of a module outside the current module scope. Detection of this issue was introduced in QUnit 3.0.
Error: Cannot add beforeEach hook outside the containing module.
Error: Cannot add afterEach hook outside the containing module.
Called on "X", instead of expected "Y".
This can happen if you use a module scope and forget to specify the hooks
parameter on the inner scope:
QUnit.module('MyGroup', (hooks) => {
QUnit.module('Child', () => {
// ^ Oops, forgot "hooks" here!
hooks.beforeEach(() => {
// ...
});
QUnit.test('example');
});
});
Another way that this might happen is if you have named them differently, or perhaps misspelled one, and are referring to the outer parameter from the inner module. Is is recommended to name hooks parameters the same, as this will naturally refer to the correct and closest one always, thus avoiding any mistake.
QUnit.module('MyGroup', (hooksOuter) => {
QUnit.module('Child', (hooksInner) => {
hooksOuter.beforeEach(() => {
// ^ Oops, used "hooksOuter" instead of "hooksInner"!
});
QUnit.test('example');
});
});