Mocking Functions with jest.fn() in Jest
This challenge focuses on understanding and utilizing jest.fn() in Jest, a crucial tool for isolating units of code during testing. You'll be creating mock functions to replace dependencies within a module, allowing you to verify interactions and control the behavior of those dependencies without relying on their actual implementations. Mastering jest.fn() is essential for writing robust and maintainable tests.
Problem Description
You are tasked with creating a module called apiService that contains a function fetchData which is responsible for fetching data from an external API. For testing purposes, you don't want to actually make network requests. Instead, you need to mock the fetchData function using jest.fn() to control its return value and verify that it's called with the correct arguments.
Your goal is to write a Jest test that:
- Imports the
apiServicemodule. - Uses
jest.fn()to create a mock function. - Replaces the original
fetchDatafunction inapiServicewith the mock function. - Calls a function in
apiServicethat usesfetchData. - Asserts that the mock function was called with the expected arguments.
- Asserts that the function in
apiServicereturns the value returned by the mock function.
Examples
Example 1:
// apiService.ts
export const fetchData = async (url: string): Promise<string> => {
// In reality, this would make an API call
return `Data from ${url}`;
};
export const processData = async (url: string): Promise<string> => {
const data = await fetchData(url);
return `Processed: ${data}`;
};
// test.ts
import * as apiService from './apiService';
describe('apiService', () => {
it('should call fetchData with the correct URL and return processed data', async () => {
const mockFetchData = jest.fn().mockResolvedValue('Mocked Data');
apiService.fetchData = mockFetchData;
const result = await apiService.processData('https://example.com');
expect(mockFetchData).toHaveBeenCalledWith('https://example.com');
expect(result).toBe('Processed: Mocked Data');
});
});
Output: Test passes.
Explanation: The mock function mockFetchData is called with the URL 'https://example.com', and processData returns 'Processed: Mocked Data' because mockFetchData returns 'Mocked Data'.
Example 2:
// apiService.ts (same as above)
// test.ts
import * as apiService from './apiService';
describe('apiService', () => {
it('should handle fetchData errors', async () => {
const mockFetchData = jest.fn().mockRejectedValue(new Error('API Error'));
apiService.fetchData = mockFetchData;
await expect(apiService.processData('https://example.com')).rejects.toThrow('API Error');
expect(mockFetchData).toHaveBeenCalledWith('https://example.com');
});
});
Output: Test passes.
Explanation: The mock function mockFetchData is called with the URL 'https://example.com', and processData throws an error because mockFetchData is configured to reject with an error.
Constraints
- The
apiService.tsfile will be provided as a starting point. You should not modify this file. - You must use
jest.fn()to create the mock function. - The test should be written in TypeScript.
- The mock function should be configured to resolve with a string value of "Mocked Data" initially.
- The test should verify that the mock function is called with the correct URL.
- The test should verify that the function in
apiServicereturns the value returned by the mock function.
Notes
- Consider using
mockResolvedValueto easily configure the mock function to resolve with a specific value. - Think about how to replace the original function with the mock function before calling the function you want to test.
- Remember to use
toHaveBeenCalledWithto verify the arguments passed to the mock function. - You can extend the test to handle error scenarios by using
mockRejectedValueandexpect(...).rejects.toThrow().