Setting up Mock Service Worker (MSW) for API Request Mocking in Jest
This challenge focuses on integrating Mock Service Worker (MSW) with Jest to effectively mock API requests during your unit tests. This is crucial for isolating your code, ensuring faster and more reliable tests, and avoiding dependencies on live API endpoints.
Problem Description
Your task is to set up Mock Service Worker (MSW) within a Jest testing environment using TypeScript. This involves configuring MSW to intercept network requests made by your application during tests and return predefined mock responses.
Key Requirements:
- Global MSW Setup: Configure MSW to run for all Jest tests in your project.
- Request Interception: Implement handlers to intercept specific API requests (e.g., GET, POST).
- Mock Responses: Provide realistic mock data for intercepted requests.
- TypeScript Integration: Ensure the setup is fully compatible with TypeScript.
- Jest Integration: Make sure MSW works seamlessly with Jest's test runner.
Expected Behavior:
When a test runs that triggers a network request intercepted by your MSW setup, the test should receive the mock response defined in your MSW handlers, rather than making an actual network call.
Edge Cases to Consider:
- Handling different HTTP methods (GET, POST, PUT, DELETE, etc.).
- Mocking responses for various status codes (200, 404, 500, etc.).
- Testing scenarios with dynamic request bodies or query parameters.
Examples
Let's assume you have a simple function that fetches user data:
// src/api/userService.ts
export interface User {
id: number;
name: string;
email: string;
}
export async function fetchUser(userId: number): Promise<User> {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`Failed to fetch user: ${response.statusText}`);
}
return response.json();
}
Example 1: Successful User Fetch
Test Setup:
Configure MSW to mock a GET request to /api/users/1.
Test Code:
// src/api/userService.test.ts
import { fetchUser } from './userService';
import { server } from '../mocks/server'; // Assume this is your MSW server setup
describe('userService', () => {
it('should fetch user data successfully', async () => {
const mockUser = { id: 1, name: 'John Doe', email: 'john.doe@example.com' };
// MSW handler configured to mock this specific request
// server.use(rest.get('/api/users/:userId', (req, res, ctx) => { ... }));
const user = await fetchUser(1);
expect(user).toEqual(mockUser);
});
});
Expected Output from fetchUser(1):
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}
Explanation:
The fetchUser(1) call is intercepted by MSW. The configured handler returns the mockUser object, which is then asserted against in the test.
Example 2: User Not Found (404)
Test Setup:
Configure MSW to mock a GET request to /api/users/99 that returns a 404 status.
Test Code:
// src/api/userService.test.ts
import { fetchUser } from './userService';
import { server } from '../mocks/server';
import { rest } from 'msw'; // Assuming you are using REST handlers
describe('userService', () => {
it('should throw an error if user is not found', async () => {
// MSW handler configured to mock this specific request with a 404
server.use(
rest.get('/api/users/:userId', (req, res, ctx) => {
return res(ctx.status(404), ctx.json({ message: 'User not found' }));
})
);
await expect(fetchUser(99)).rejects.toThrow('Failed to fetch user: Not Found');
});
});
Expected Output from fetchUser(99):
The fetchUser function will throw an error with a message like "Failed to fetch user: Not Found".
Explanation:
The GET request for /api/users/99 is intercepted. The MSW handler returns a 404 status code and a JSON error message. The fetchUser function, upon receiving a non-ok response, throws an error, which is then caught and asserted by expect(...).rejects.toThrow().
Constraints
- Your MSW setup should be configured to run globally for all Jest tests.
- You must use TypeScript for your setup and handlers.
- The solution should be performant, ensuring tests do not become excessively slow due to the mocking setup.
- All API requests within your application's scope should be interceptable by MSW.
Notes
- Consider using
jest-setup-after-env.tsfor global Jest setup. - MSW offers different types of handlers (REST, GraphQL). For this challenge, focus on REST handlers.
- Think about how to organize your mock handlers for maintainability.
- Ensure you have installed the necessary MSW and Jest packages.
- The core of this challenge is setting up the
serverinstance and integrating it with Jest's setup lifecycle.