How to Test Async Code in JavaScript: Simple Guide
To test
async code in JavaScript, use async/await or return a Promise in your test function so the test runner knows to wait. Testing frameworks like Jest support this by allowing tests to be declared async or by returning promises.Syntax
Testing async code usually involves one of these patterns:
- Async/Await: Mark the test function as
asyncand useawaitinside it. - Returning a Promise: Return a
Promisefrom the test function so the test runner waits for it. - Callback with done: Use a
donecallback parameter and call it when async work finishes (less common now).
javascript
test('async test with async/await', async () => { const data = await fetchData(); expect(data).toBe('hello'); }); // Or returning a Promise test('async test returning promise', () => { return fetchData().then(data => { expect(data).toBe('hello'); }); }); // Using done callback (legacy) test('async test with done callback', done => { fetchData().then(data => { expect(data).toBe('hello'); done(); }); });
Example
This example shows how to test an async function that returns a promise using async/await in Jest. It waits for the async function to complete and checks the result.
javascript
function fetchData() { return new Promise(resolve => { setTimeout(() => { resolve('hello'); }, 100); }); } test('fetchData returns hello', async () => { const result = await fetchData(); expect(result).toBe('hello'); });
Output
PASS fetchData returns hello
Common Pitfalls
Common mistakes when testing async code include:
- Not returning the promise or not using
asyncin the test, causing the test to finish before the async code runs. - Forgetting to call
done()when using the callback style, which makes tests hang or timeout. - Mixing callback and promise styles incorrectly.
javascript
/* Wrong: test finishes before async code runs */ test('wrong async test', () => { fetchData().then(data => { expect(data).toBe('hello'); }); }); /* Right: return the promise or use async/await */ test('right async test', () => { return fetchData().then(data => { expect(data).toBe('hello'); }); }); // Or test('right async test with async/await', async () => { const data = await fetchData(); expect(data).toBe('hello'); });
Quick Reference
Summary tips for testing async code:
- Use
async/awaitfor clear and readable tests. - Always return a
Promiseor mark the testasyncso the test runner waits. - Avoid mixing callback
donestyle with promises unless necessary. - Use
try/catchinside async tests to handle errors gracefully.
Key Takeaways
Mark test functions as async or return a Promise to properly test async code.
Use async/await for simpler and more readable async tests.
Avoid forgetting to return promises or call done(), which causes false positives or hanging tests.
Handle errors inside async tests with try/catch to avoid unhandled rejections.
Prefer modern async/await style over callback done() style for clarity.