Mocking API Responses with Jest in TypeScript
Testing asynchronous functions that fetch data from APIs can be tricky. To isolate your code and ensure it behaves correctly regardless of external dependencies, you often need to mock the API calls and control the returned data. This challenge focuses on creating mock return values for functions that use fetch in a TypeScript environment using Jest.
Problem Description
You are tasked with creating a Jest test for a function called fetchUserData which fetches user data from a specified URL using the fetch API. The goal is to mock the fetch function to return a predefined response, allowing you to test the fetchUserData function's logic without actually making a network request. You need to ensure that the mocked fetch function is called with the correct URL and that the fetchUserData function correctly parses the mocked response.
What needs to be achieved:
- Mock the
fetchfunction using Jest'sjest.spyOn. - Configure the mock to return a specific response object (including
statusandjsonmethods). - Assert that
fetchwas called with the expected URL. - Assert that
fetchUserDatacorrectly processes the mocked response.
Key requirements:
- The
fetchUserDatafunction should accept auserIdas an argument and construct the URL accordingly. - The mocked
fetchfunction should be called with the correct URL. - The mocked response's
json()method should return a promise that resolves to a specific user object. - The test should assert that the
fetchUserDatafunction returns the expected user object.
Expected behavior:
The test should pass if the fetch function is mocked correctly, the mock is called with the expected URL, and the fetchUserData function processes the mocked response as expected.
Edge cases to consider:
- Ensure the URL is constructed correctly based on the
userId. - The mocked response should simulate a successful HTTP request (status 200).
- The
json()method of the mocked response should return a promise.
Examples
Example 1:
Input: userId = 123
Mocked Response: { json: () => Promise.resolve({ id: 123, name: 'John Doe' }) }
Output: { id: 123, name: 'John Doe' }
Explanation: fetchUserData(123) should fetch from 'https://api.example.com/users/123', mock fetch to return a user object, and the test should assert that the returned user object is { id: 123, name: 'John Doe' }.
Example 2:
Input: userId = 'abc'
Mocked Response: { json: () => Promise.resolve({ id: 'abc', name: 'Jane Smith' }) }
Output: { id: 'abc', name: 'Jane Smith' }
Explanation: fetchUserData('abc') should fetch from 'https://api.example.com/users/abc', mock fetch to return a user object, and the test should assert that the returned user object is { id: 'abc', name: 'Jane Smith' }.
Constraints
- The
fetchUserDatafunction is defined as follows:
async function fetchUserData(userId: string | number): Promise<{ id: string | number; name: string }> {
const url = `https://api.example.com/users/${userId}`;
const response = await fetch(url);
return await response.json();
}
- You must use
jest.spyOnto mock thefetchfunction. - The mocked response must have a
json()method that returns a promise. - The test should be written in TypeScript.
Notes
- Consider using
jest.mockif you want to mock the entirefetchmodule, butjest.spyOnprovides more granular control. - Pay close attention to the asynchronous nature of
fetchand promises. Useasync/awaitor.then()appropriately. - Think about how to verify that the correct URL was used in the
fetchcall.mockImplementationcan be helpful here. - The base URL
https://api.example.com/users/is fixed and should not be changed in your test.