Using Jasmine's done() Callback to Test Asynchronous Code Reliably
Learn how Jasmine's done() callback prevents flaky async tests by pausing specs until asynchronous work finishes, with a concrete setTimeout example and practical verification steps.
13 Feb 2026, 14:45 UTC

When a Jasmine spec finishes before an asynchronous operation completes, the test can pass or fail for the wrong reason. This happens because Jasmine’s default test runner assumes synchronous execution and moves on to the next spec as soon as the test function returns.
Why done() solves the problem
Jasmine provides a done callback that you can place as the first argument of a test function. When Jasmine detects this argument, it pauses the spec’s completion until done() is invoked. If the callback is never called, Jasmine aborts the spec after its default timeout (typically 5 seconds) and reports a timeout error.
How the callback works
- You write the spec as
function(done) { … }. - Inside the function you start the async work (e.g.,
setTimeout, a Promise, or an XHR). - When the async work finishes, you call
done(). - Jasmine then marks the spec as complete and evaluates any expectations that ran before the callback.
If you forget to call done(), the spec times out. If you call it more than once, Jasmine throws an error about multiple invocations.
Worked example: testing a setTimeout
The following spec verifies that a timeout of 10 ms sets a flag correctly. It uses done() to tell Jasmine to wait for the timer.
describe('Async flag with setTimeout', function() {
it('sets the flag after the timeout', function(done) {
let flag = false;
setTimeout(() => {
flag = true;
expect(flag).toBe(true); // expectation runs before done()
done(); // signals Jasmine the async work is done
}, 10);
});
});
Run this spec with the Jasmine CLI:
jasmine spec/asyncFlag.spec.js
You should see a passing test that completes well before the default 5‑second timeout.
Trade‑offs and limitations
- Exact invocation required: Forgetting or duplicating
done()leads to timeout errors or “done() called multiple times” failures. - Mixing with async/await: If you declare the test as
async function()and also accept adoneparameter, Jasmine may treat the spec as both promise‑based and callback‑based, causing double‑resolution warnings or hanging specs. - Timeout value: The default interval is configurable (
jasmine.DEFAULT_TIMEOUT_INTERVAL), but changing it globally can mask real performance issues.
Actionable closing
To use done() safely:
- Always place
doneas the first (and only) callback argument. - Call it exactly once, after all assertions that depend on the async result.
- Prefer
async/await for Promise‑based code when possible; it eliminates the need fordone(). - Verify your Jasmine version (
jasmine -v) – thedone()API has been stable since Jasmine 2.0 and works in the current 4.x line.
By following these steps, your asynchronous specs will run deterministically, giving you confidence that passes and failures reflect the actual behavior of your code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.