Async/Await in Tests
Async/Await in Tests
Basic Async Test
// Async function
describe('fetchUser', () => {
it('should return user data', async () => {
const user = await fetchUser(1);
expect(user).toEqual({ id: 1, name: 'John' });
});
});
Async Component Test
import { render, screen, waitFor } from '@testing-library/react';
describe('UserProfile', () => {
it('should display user name after loading', async () => {
render(<UserProfile id={1} />);
// Wait for loading to complete
await waitFor(() => {
expect(screen.getByText('John')).toBeInTheDocument();
});
});
it('should show error on failure', async () => {
// Mock API error
server.use(
http.get('/api/users/1', () => {
return HttpResponse.json(null, { status: 500 });
})
);
render(<UserProfile id={1} />);
await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('Error');
});
});
});
findBy Query
// findBy waits for element automatically
describe('SearchResults', () => {
it('should display results', async () => {
render(<SearchResults query="react" />);
// findByText waits for element to appear
const result = await screen.findByText('React Results');
expect(result).toBeInTheDocument();
});
});
Timer Mocks
Timer Mocks
Jest Fake Timers
// Use fake timers
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
describe('debounce', () => {
it('should delay execution', () => {
const fn = jest.fn();
const debounced = debounce(fn, 300);
debounced();
expect(fn).not.toHaveBeenCalled();
// Fast forward time
jest.advanceTimersByTime(300);
expect(fn).toHaveBeenCalledTimes(1);
});
});
Async Timer Tests
describe('delay', () => {
it('should resolve after delay', async () => {
const promise = delay(1000);
jest.advanceTimersByTime(1000);
await expect(promise).resolves.toBeUndefined();
});
});
Interval Testing
describe('polling', () => {
it('should call function repeatedly', () => {
const fn = jest.fn();
startPolling(fn, 5000);
jest.advanceTimersByTime(15000);
expect(fn).toHaveBeenCalledTimes(3);
});
});
Date Mocking
// Mock specific date
const mockDate = new Date('2024-01-15T12:00:00');
jest.spyOn(global, 'Date').mockImplementation((arg) => {
if (arg) return new originalDate(arg);
return mockDate;
});
// Or use jest.mock
dateSpy.mockReturnValue(mockDate);
Animation Testing
// Mock requestAnimationFrame
window.requestAnimationFrame = jest.fn(cb => setTimeout(cb, 16));
window.cancelAnimationFrame = jest.fn(id => clearTimeout(id));
// Mock CSS animations
Element.prototype.animate = jest.fn(() => ({
finished: Promise.resolve(),
}));
Network Requests
Network Requests
MSW (Recommended)
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
const server = setupServer(
http.get('/api/data', () => {
return HttpResponse.json({ value: 42 });
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
it('should fetch data', async () => {
render(<DataComponent />);
await waitFor(() => {
expect(screen.getByText('42')).toBeInTheDocument();
});
});
Axios Mock
import axios from 'axios';
jest.mock('axios');
it('should fetch data with axios', async () => {
axios.get.mockResolvedValueOnce({
data: { id: 1, name: 'John' },
});
const user = await fetchUser(1);
expect(user).toEqual({ id: 1, name: 'John' });
expect(axios.get).toHaveBeenCalledWith('/api/users/1');
});
Error Testing
it('should handle network error', async () => {
server.use(
http.get('/api/data', () => {
return HttpResponse.error();
})
);
render(<DataComponent />);
await waitFor(() => {
expect(screen.getByText('Network error')).toBeInTheDocument();
});
});
it('should handle timeout', async () => {
server.use(
http.get('/api/data', async () => {
await delay(5000);
return HttpResponse.json({ data: 'test' });
})
);
render(<DataComponent />);
await waitFor(() => {
expect(screen.getByText('Request timeout')).toBeInTheDocument();
});
});
Request Verification
it('should send correct request', async () => {
const handler = http.post('/api/users', async ({ request }) => {
const body = await request.json();
expect(body).toEqual({ name: 'John', email: 'john@example.com' });
return HttpResponse.json({ id: 1, ...body });
});
server.use(handler);
render(<CreateUserForm />);
await userEvent.type(screen.getByLabelText('Name'), 'John');
await userEvent.type(screen.getByLabelText('Email'), 'john@example.com');
await userEvent.click(screen.getByText('Create'));
await waitFor(() => {
expect(screen.getByText('User created')).toBeInTheDocument();
});
});
Practice Problems
Create a reusable React component implementing Testing Async Code. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Testing Async Code using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Testing Async Code for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. How do you test async functions?
2. What does jest.useFakeTimers do?
3. What is the primary purpose of Testing Async Code?
4. What is a common mistake when implementing Testing Async Code?
Flashcards
Question
How do you test async code?
Click to reveal answer
Answer
Use async/await, waitFor for assertions, and findBy queries for elements.
Question
What are fake timers?
Click to reveal answer
Answer
Mocks for setTimeout/setInterval that let you control time in tests.
Question
How do you test network errors?
Click to reveal answer
Answer
Configure MSW to return error responses and verify error handling.
Question
What is the findBy query?
Click to reveal answer
Answer
An async query that waits for an element to appear in the DOM.
Question
What is Testing Async Code?
Click to reveal answer
Answer
Testing Async Code is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Use async/await for clean async tests
- 2.waitFor retries assertions until timeout
- 3.Fake timers control setTimeout/setInterval
- 4.MSW provides realistic API mocking
- 5.findBy queries wait for elements automatically
Interview Tips
- •Explain how to test async code
- •Discuss fake timers and when to use them
- •Know how to test network requests and errors
Cheat Sheet
Testing Async Cheat Sheet
Async/Await
it('should work', async () => {
const result = await asyncFunction();
expect(result).toBe(expected);
});
waitFor
await waitFor(() => {
expect(screen.getByText('Done')).toBeInTheDocument();
});
Fake Timers
jest.useFakeTimers();
jest.advanceTimersByTime(1000);
MSW
server.use(
http.get('/api', () => HttpResponse.json(data))
);