Use comparing functions such as
propEqual(). Avoid passing expressions to
Letting QUnit perform the comparison has several advantages:
- Allows the test runner to display the difference between the expected and actual values. When using
ok()it forces one to do inline expression, which loses this information. This is especially important when working with test reports generated externally (eg. from Jenkins or Karma) in which case the test output is all you have. (When running tests manually in a browser locally, one could set breakpoints etc.)
- Passing an explicit expected value serves to self-document the expected result.
- Using an explicit expected value avoids accidentally hiding regressions as result of type casting and non-strict comparisons.
// Not very useful, the comparison is done inline and ok() // can only know about the result of the comparison var x = 'foo'; assert.ok( x === 'bar' ); // Failed. assert.ok( x === 'foo' ); // Passed.
// Useful! The unit test is given both values, // allowing it also mention both in the output: var x = 'foo'; assert.strictEqual( x, 'bar' ); // Failed. Expected: "bar". Result: "foo" assert.strictEqual( x, 'foo' ); // Passed. Expected: "foo".
In cases where the exact value is too variable or doesn't matter, you can still make an explicit comparison by checking its type (in case of a function), or its length (in case of an array or string). For example:
// 1) Bad example: // - Fails or passes without other information. // - Tolerates too many outcomes that are not expected. assert.ok( mw.Example, 'Quux is defined' ); assert.ok( mw.foo.barName, 'Name is set' ); assert.strictEqual( typeof mw.Example, 'function', 'Quux is defined' ); // Failed. Expected: "function". Result: "undefined" // Passed. Expected: "function". assert.strictEqual( typeof mw.foo.barName, 'string', 'Name is set' ); // Failed. Expected: "string". Result: "number" // Passed. Expected: "string".
When dealing with objects (such as arrays, object literals, or other objects) one can't use
equal to compare the content. In such case one has to use
propEqual, which will loop over the object and compare each key/value separately. For example:
var a = ['foo', 'bar']; assert.equal(a, ['foo', 'bar'], 'The array'); assert.strictEqual(a, ['foo', 'bar'], 'The array'); // Failed, because objects are compared by identity. assert.deepEqual(a, ['foo', 'bar'], 'The array.'); // Passed. Expected: ['foo', 'bar']
Test elements edit
The QUnit runner automatically ensures the
<div id="qunit-fixture"></div> element exists and is cleaned by QUnit before each test. Use this for any elements that need to be connected to the document. Avoid appending nodes elsewhere in the document as they may be left behind and affect other tests.
Tests that assert the outcome of an asynchronous method (or a method that returns a promise), should have their return value returned from the
QUnit.test() function. This allows QUnit to automatically track the promise without manually having to connect it with
assert.async. This has the benefit of also automatically asserting that the Promise is resolved, and failing the test with the rejection error if the promise was rejected. No manual
assert.ok(true/false) statements needed.
If an asynchronous method is expected to be rejected rather than resolved, one can use
assert.rejects(), which behaves the same as returning a Promise to QUnit.test, except that it expects rejection rather than resolution.
Lastly, if a test is asynchronous but does not naturally provide a Promise, you can use
assert.async() to manually track it. This is preferred over creating custom Promise or Deferred wrappers.
Data sourcing/seeding in Ajax requests edit
Because QUnit tests shouldn't depend by the data registered on the back-end (unless the test is not meant to verify a specific data-set available by default upon installation) the Ajax calls performed during tests requests should be handled using the following strategy:
- if the result of an Ajax request only depends from the data provided by the client, or additional data retrieved on the server do not depend by a specific data-set, then a real Ajax request can be performed during the test, and the test can be verified either using
assert.asyncin conjunction with
doneor using a trigger
- if the result of an Ajax request depends by a specific data-set registered on the back-end, then the result should be either overridden with data provided by the QUnit function, or the success callback should be directly executed with the provided data without performing the Ajax request.