Manual Mock Implementation in Jest
This challenge focuses on understanding and implementing manual mocks in Jest. Manual mocks allow you to precisely control the behavior of dependencies within your unit tests, isolating the code under test and ensuring predictable results. This is crucial for testing components that rely on external services, modules, or functions.
Problem Description
You are tasked with creating a manual mock for a function called fetchData which is used within a module called apiService. The fetchData function is responsible for fetching data from an external API. Your goal is to create a Jest mock that allows you to control the data returned by fetchData during your tests, without actually making a network request.
Specifically, you need to:
- Create a mock implementation of
fetchDatathat accepts a URL as an argument. - The mock should allow you to specify a
responseobject to return when called. Thisresponseobject should have ajsonmethod that resolves to a specifiedmockData(also provided by the test). - The mock should be applied to the
apiServicemodule before the module is imported into the component being tested. - Write a test case that uses the mock to verify that a component correctly handles a specific response from
fetchData.
Examples
Example 1:
Input:
apiService.ts:
export const fetchData = async (url: string): Promise<any> => {
const response = await fetch(url);
return response.json();
};
Component.ts:
import { fetchData } from './apiService';
export const Component = async () => {
const data = await fetchData('https://example.com/data');
return `Data: ${data.message}`;
};
Test.test.ts:
// Test file
// Expected Output (in test):
// "Data: Mocked Message"
Explanation: The test should mock fetchData to return a response object with a json method that resolves to { message: 'Mocked Message' }. The component should then render "Data: Mocked Message".
Example 2:
Input:
apiService.ts:
export const fetchData = async (url: string): Promise<any> => {
const response = await fetch(url);
return response.json();
};
Component.ts:
import { fetchData } from './apiService';
export const Component = async () => {
const data = await fetchData('https://example.com/data');
if (data.success) {
return `Success: ${data.result}`;
} else {
return `Error: ${data.error}`;
}
};
Test.test.ts:
// Test file
// Expected Output (in test):
// "Error: Mocked Error"
Explanation: The test should mock fetchData to return a response object with a json method that resolves to { success: false, error: 'Mocked Error' }. The component should then render "Error: Mocked Error".
Constraints
- The mock must be implemented manually using
jest.fn()and not rely onjest.mock()with auto-mocking. - The
fetchDatafunction is asynchronous and returns a Promise. Your mock must also return a Promise. - The mock must be applied before the
apiServicemodule is imported into the component being tested. - The test should use
async/awaitfor clarity. - The mock should accept a URL argument, but the URL itself is not important for the test; only the returned data matters.
Notes
- Consider how to create a
responseobject that mimics the behavior of the actualfetchAPI. Remember thatfetchreturns aResponseobject, which has ajson()method. - Think about how to use
jest.fn()to create a mock function and how to control its return value. - This exercise is about understanding the fundamentals of manual mocking. Focus on creating a clear and controllable mock, rather than complex logic within the mock itself.
- The
mockDatashould be a simple JavaScript object.