Testing async function with jasmine
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Asynchronous code is everywhere in JavaScript, from HTTP calls to timers and event streams. Jasmine supports several async testing styles, but each style has specific failure modes if used incorrectly. This guide shows reliable patterns for Promise-based and callback-based code, with examples you can run directly.
Test Promises with async and await
For modern JavaScript, async and await is the cleanest approach. Jasmine waits for the returned Promise to settle.
If the Promise rejects and you do not handle it, Jasmine marks the spec as failed automatically.
Test Callback APIs with done
Some legacy APIs use callbacks instead of Promises. In that case, Jasmine done is still useful.
Always call done.fail(error) on error paths so failures are visible.
Control Timer-Based Async Logic
For code using setTimeout or setInterval, use Jasmine fake clock to avoid slow tests.
This gives deterministic timing without setTimeout in test code.
Test Rejection and Error Paths Explicitly
Async bugs often hide in unhappy paths, so write dedicated rejection tests.
expectAsync makes rejection assertions concise and readable.
Keep Async Tests Deterministic
Stable async tests usually follow a few simple rules.
- Do not rely on real network access. Stub dependencies and resolve promises locally.
- Avoid shared mutable state across specs.
- Keep one async style per test. Do not combine
doneandasyncin the same spec. - Use explicit timeouts only when necessary and keep them short.
If a test suite is flaky, start by removing real timers and real I/O.
Tune Timeouts for CI Stability
Async tests that pass locally can fail in CI due to slower workers. Set a reasonable default timeout and override only when a spec really needs more time.
Avoid extreme values that hide performance regressions. If a test needs long timeouts regularly, it usually indicates real external I/O or poor isolation.
For browser-based suites, ensure microtask queues are flushed consistently between tests. For Node-based suites, reset spies and fake timers in afterEach so one spec does not leak state into another.
Common Pitfalls
- Forgetting to return or await a Promise, causing false-positive passing tests.
- Calling
donetwice, which can produce confusing failures. - Using
donein a test that already returns a Promise. - Depending on actual wall-clock delays instead of fake timers.
- Not testing rejection paths, which leaves error handling unverified.
Summary
- Prefer
asyncandawaitfor Promise-based APIs. - Use
doneonly for callback-style APIs and calldone.failon errors. - Use
jasmine.clockfor deterministic timer tests. - Assert both success and failure paths with
expectAsync. - Keep tests isolated from real network and timing dependencies.
Related reading
- Testing Complex Asynchronous Redux Actions
- tf.data Parallelize loading step
- TFRecordReader seems extremely slow , and multi-threads reading not working
- The best way to sync ActiveRecord structure between rails apps
- tfjs_binding.node not found in tensorflow installed folder
- tf.loadModel is not a function
- Testing GPU with tensorflow matrix multiplication
- Testing locally k8s distributed system
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.