Guide
Jasmine Async Test Hangs: A Diagnostic Guide for done() Callback and Promise Issues
When Jasmine async tests hang, the issue is typically improper done() callback invocation or missing promise returns. This diagnostic guide provides checks and fixes for common async testing problems.
Published by Tasadduq Burney
26 Nov 2025, 06:36 UTC
3 min66.4K views0

The Problem: Tests That Never Complete
When a Jasmine test containing asynchronous operations appears to hang indefinitely, the most common culprits are improper done() callback invocation or missing promise returns. This diagnostic guide walks through recognizing the condition and applying targeted fixes.
Recognizable Condition
- Test runner stops responding after an async test starts
- Console shows no failures but test never progresses
- Timeout errors appear after 5+ seconds (Jasmine's default)
- Subsequent tests in the same
describeblock don't execute
Diagnostic Table: Common Causes and Their Signatures
| Symptom | Root Cause | Diagnostic Check |
|---|---|---|
| Test hangs, no completion message | done() never called |
Search for done parameter in test function but no invocation |
| Async test passes but suite stops | Promise not returned | Check if async function returns a promise without return statement |
Intermittent failures with setTimeout |
Callback timing race condition | Verify done() called inside callback, not outside |
| Spies report calls from previous tests | State leakage between tests | Check for missing spy.cleartAllCalls() in afterEach |
Ordered Diagnostic Checks
- Identify async pattern used: Determine if the test uses
done()callback or returns a promise. - Verify done() invocation: If using
doneparameter, confirm it's called exactly once at the end of async operation. - Check promise return: If returning a promise, ensure it's explicitly returned, not just passed as argument.
- Examine setTimeout usage: Confirm
done()is called inside the timeout callback, not before it. - Validate spy cleanup: Ensure spies are reset in
afterEachto prevent cross-test contamination.
Concrete Example: Fixing a Hanging Test
Problematic code:
it('fetches user data', function(done) {
fetch('/api/user/1')
.then(response => response.json())
.then(data => {
expect(data.name).toBe('John');n });
// done() never called - test hangs
});
Fixed version:
it('fetches user data', function(done) {
fetch('/api/user/1')
.then(response => response.json())
.then(data => {
expect(data.name).toBe('John');n done(); // Signal completion
});
});
Alternative with promise return:
it('fetches user data', function() {
return fetch('/api/user/1')
.then(response => response.json())
.then(data => {
expect(data.name).toBe('John');
});
});
Verification Steps
- Run the specific test file:
npx jasmine spec/async-test.spec.js --timeout=10000 - Observe that test completes within expected time
- Check that subsequent tests execute normally
- Verify no state leakage in spy-based tests
Limitations and Important Notes
done()must be called exactly once; calling it multiple times throws an error- Promise-based async tests cannot use
done()parameter - choose one pattern only - Jasmine 2.x and later handle async differently than early versions; ensure version compatibility
beforeEach/afterEachwith async operations require the same patterns asitblocks
Escalation Criteria
If the above checks don't resolve the hanging issue, escalate to:
- Check for unhandled promise rejections in the test output
- Verify Jasmine configuration timeout setting (
jasmine.DEFAULT_TIMEOUT_INTERVAL) - Consider using
fail()explicitly in error handlers to surface silent failures - Review test framework integration (e.g., Karma, Jasmine CLI) for configuration issues
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.