Mocking API Responses in Jest for Unit Testing
In modern web development, it's common to interact with external services or APIs. When writing unit tests for your application logic, you often don't want to (or can't) actually make network requests. Mocking allows you to simulate the behavior of these external dependencies, providing predictable return values for your tests. This challenge focuses on using Jest to create mock return values for functions that simulate API calls.
Problem Description
You are tasked with writing unit tests for a TypeScript function that fetches user data from an external API. This function relies on another module that handles the actual API communication. Your goal is to isolate the function you're testing by mocking the API communication module. You need to ensure that your tests can control the responses from this mocked module, including successful data retrieval and error scenarios.
Key Requirements:
- Create a mock implementation for a module that performs API calls.
- Configure the mock to return specific data for a successful API call.
- Configure the mock to simulate an API error.
- Write a unit test for a function that consumes this API.
Expected Behavior:
When the function under test is called, it should:
- If the mocked API call succeeds, return the data provided by the mock.
- If the mocked API call fails, throw an error as provided by the mock.
Edge Cases to Consider:
- What happens if the API returns an empty array or null for a successful call?
- What happens if the API throws a specific type of error?
Examples
Example 1: Successful API Call
Let's assume we have a module apiService with a function fetchUserData(userId: string): Promise<User>.
Input (for the function under test):
fetchUserDataFromService('user-123')
Mocked apiService.fetchUserData return value:
A Promise that resolves with the following user object:
{
"id": "user-123",
"name": "Alice Smith",
"email": "alice.smith@example.com"
}
Output (from the function under test):
{
"id": "user-123",
"name": "Alice Smith",
"email": "alice.smith@example.com"
}
Explanation: The fetchUserDataFromService function, when its dependency apiService.fetchUserData is mocked to return a specific user object, successfully retrieves and returns that user object.
Example 2: API Error Scenario
Input (for the function under test):
fetchUserDataFromService('user-456')
Mocked apiService.fetchUserData return value:
A Promise that rejects with an Error object:
new Error("Network Error: Failed to fetch user data.")
Output (from the function under test): The function should throw the same error:
throw new Error("Network Error: Failed to fetch user data.")
Explanation: When the mocked API call rejects with an error, the fetchUserDataFromService function correctly propagates that error.
Constraints
- Your solution should be written in TypeScript.
- You must use Jest for your unit testing framework.
- The mock for
apiServiceshould be created usingjest.mock. - The mock should simulate asynchronous behavior (Promises).
Notes
Consider how you will structure your project to facilitate mocking. You might have a service layer that wraps your API calls. Focus on how to mock that service layer within your Jest tests. Think about how jest.mock works and how to provide custom implementations for mocked functions. You can use jest.fn() to create mock functions and then control their return values using methods like .mockResolvedValue() or .mockRejectedValue().