Testing Asynchronous Code with Jasmine’s done() Callback
Learn how to write reliable Jasmine tests for async code using the done() callback, with setup, example, verification steps, and recovery tips.
21 Jul 2026, 22:03 UTC

Desired Outcome
Write a Jasmine test that reliably passes or fails based on the completion of an asynchronous operation (e.g., a timer, a Promise, or an AJAX request) using the done() callback.
Prerequisites
- Node.js version 12 or newer installed.
- Jasmine installed as a dev dependency in your project (
npm i -D jasmine) or available globally. - A test file that follows Jasmine’s
describe/itstructure (e.g.,spec/asyncSpec.js). - Basic familiarity with running Jasmine from the command line (
npx jasmine).
Focused Procedure
- Create the test file – open
spec/asyncSpec.jsand add adescribeblock. - Define an
itblock that accepts adoneparameter – this tells Jasmine the test is asynchronous. - Perform the async work – for demonstration we use
setTimeout, but the same pattern applies to Promises or XHR/fetch calls. - Call
done()when the operation succeeds – pass an error argument (done(err)) if you want the test to fail. - Save the file and run Jasmine from the project root.
// spec/asyncSpec.js
const fetch = require('node-fetch'); // only needed if you test HTTP
describe('Async operation with done()', () => {
it('should resolve after a short timeout', (done) => {
setTimeout(() => {
// Simulate successful work
const result = 'ok';
if (result === 'ok') {
done(); // success
} else {
done(new Error('unexpected result')); // failure with error
}
}, 10); // 10 ms delay
}),
it('should reject a Promise and fail the test', (done) => {
Promise.reject(new Error('network error'))
.catch(err => done(err)); // pass error to done
}),
// Example using fetch (requires node-fetch or similar)
it('should fetch a JSON placeholder', (done) => {
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(res => res.json())
.then(data => {
if (data.id === 1) done();
else done(new Error('wrong data'));
})
.catch(err => done(err));
});
});
Expected Checks
- If
done()is invoked without arguments before Jasmine’s default timeout (5 seconds), the test is marked passed. - If
done(err)is called with an error, or the timeout expires without a call, the test is marked failed and Jasmine reports a timeout error. - Calling
done()more than once throws an internal Jasmine error:Error: done() called multiple times, which also results in a failure.
Recovery Options & Best Practices
- Increase the timeout for slow operations – set
jasmine.DEFAULT_TIMEOUT_INTERVALin abeforeAllblock or injasmine.json.// in spec/support/jasmine.json or a beforeAll jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000; // 15 seconds - Ensure exactly one call to
done()– wrap the async logic in a try/catch and calldoneonly in thefinallyblock or after checking that it hasn’t been called yet. - Prefer returning a Promise or using async/await when possible – Jasmine natively handles returned promises, eliminating the need for
done(). Example:it('works with async/await', async () => { await new Promise(r => setTimeout(r, 5)); expect(true).toBe(true); }); - Avoid mixing styles – do not return a value and also call
done()in the sameitblock; choose one approach per test.
Limitations and Practical Verification
The done() callback relies on Jasmine’s internal timeout mechanism. If the test environment is heavily loaded, a legitimate async operation might exceed the default 5 seconds and cause a false‑negative. To verify that your timeout setting works:
- Create a test that deliberately waits longer than the current timeout (e.g., 6000 ms).
- Run Jasmine – you should see a timeout failure.
- Adjust
jasmine.DEFAULT_TIMEOUT_INTERVALto a value greater than the wait (e.g., 10000 ms) and re‑run; the test should now pass.
Another practical check is to intentionally omit done(); the test will hang until the timeout expires and then fail with a clear message, confirming that Jasmine is monitoring the callback.
Summary
Using Jasmine’s done() callback lets you synchronize tests with asynchronous code. Follow the procedure above, verify the behavior with the provided checks, and apply the recovery options to avoid common pitfalls such as missed or duplicate calls.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.