Custom Jest Test Environment for Mocking APIs
This challenge focuses on creating a custom Jest test environment to mock external API responses. This is a crucial skill for ensuring reliable and isolated unit tests, preventing your tests from depending on the actual availability and state of external services. You will build a reusable environment that can be configured to return specific mock data for your API calls.
Problem Description
You need to implement a custom Jest test environment that allows you to easily mock HTTP requests made by your application during testing. This environment should be configurable to return specific mock responses for different API endpoints and HTTP methods.
Key Requirements:
- Custom Environment Setup: Create a custom Jest environment that extends Jest's default environment.
- Mocking Library Integration: Utilize a library like
msw(Mock Service Worker) orjest-mock-extendedto intercept and mock HTTP requests. For this challenge, we will focus on usingmsw. - Configurable Mock Responses: The environment should allow for defining a set of mock handlers that can be dynamically configured for different test suites.
- Teardown and Reset: Ensure that mock handlers are correctly set up before tests run and cleaned up afterwards to prevent test pollution.
- Testing an Example Service: Create a simple TypeScript function that makes an API call to demonstrate the custom environment's functionality.
Expected Behavior:
When tests are run using this custom environment, any HTTP requests made by the application code should be intercepted by the mock handlers. The application code should receive the mock responses as if they came from the actual API.
Edge Cases to Consider:
- Handling different HTTP methods (GET, POST, PUT, DELETE).
- Handling requests to different endpoints.
- Returning various HTTP status codes (e.g., 200 OK, 404 Not Found, 500 Internal Server Error).
- Ensuring mocks are correctly reset between test files or test suites.
Examples
Let's imagine you have a userService.ts that fetches user data from an API:
// userService.ts
export interface User {
id: number;
name: string;
}
export async function getUser(userId: number): Promise<User> {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`Failed to fetch user: ${response.statusText}`);
}
return response.json();
}
Example 1: Successful User Fetch
Input:
(Test setup uses custom environment to mock GET https://api.example.com/users/1 to return { id: 1, name: "Alice" })
Running `getUser(1)` in a test file.
Output:
{ id: 1, name: "Alice" }
Explanation:
The custom environment intercepts the `fetch` call to `https://api.example.com/users/1`. The mock handler is configured to return a successful JSON response with the specified user data. `getUser` receives this mock data and returns it.
Example 2: User Not Found
Input:
(Test setup uses custom environment to mock GET https://api.example.com/users/99 to return a 404 Not Found status)
Running `getUser(99)` in a test file.
Output:
An error is thrown: "Failed to fetch user: Not Found" (or similar depending on fetch implementation)
Explanation:
The custom environment intercepts the `fetch` call. The mock handler is configured to simulate a 404 response. The `getUser` function checks `response.ok` and throws an error accordingly.
Constraints
- The solution must be implemented in TypeScript.
- Jest must be used as the test runner.
msw(Mock Service Worker) should be used for mocking HTTP requests.- The custom environment should be correctly configured in
jest.config.js. - Tests should be written using Jest's standard
describeanditblocks.
Notes
- You'll need to set up a
jest.config.jsfile to specify your custom environment. - Consider how to structure your mock handlers to make them reusable and easy to manage.
- Think about the lifecycle of your custom environment: when should mocks be set up and torn down?
- You might want to explore different ways to inject or configure the mock handlers for your tests (e.g., passing them to the environment constructor, setting them via Jest setup files).
- The
setupFilesAfterEnvoption in Jest can be useful for initializing mocks globally for your test suite.