When building modern web applications, testing API interactions is crucial for ensuring robust applications. Developers can mimic API calls without actually reaching endpoints by using the robust retrieve request mimicking facilities provided by Jest, a well-known JavaScript testing framework.
This method offers a controlled environment for comprehensive API testing in addition to expediting test execution.
Read More: Jest Framework Tutorial: How to use it
What is Mock Fetch Request in Jest?
Developers can test how their code communicates with APIs without actually sending network queries by using Jest’s mock fetch request. This makes it possible for the code to function properly in a variety of situations without depending on external services.
Developers can create a fake function in Jest using the jest.fn() tool to mock fetch requests.
global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ data: 'mocked data' }), ok: true, status: 200 }) );
This setup creates a mock fetch function that returns a Promise resolving to an object with a json method, ok status, and status code. These values can be altered to suit any particular testing requirements.
Types of Mock Fetching in Jest
Manual Mock Fetch and Auto Mock Fetch are the two main methods for mimicking fetch requests that Jest provides. By simulating API calls without actually submitting network queries, these techniques give developers a controlled testing environment.
Manual Mock Fetch
Manual mocking involves overriding the global fetch function with a custom implementation. This approach gives developers fine-grained control over the mock’s behavior.
global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ data: 'mocked data' }), ok: true, status: 200 }) );
Although this approach calls for extra setup, it provides flexibility in creating specific responses for several situations.
Auto Mock Fetch
Auto mocking simplifies the process by using third-party libraries like jest-fetch-mock. This method lowers the amount of boilerplate code and offers practical means of simulating fetch requests
import fetchMock from "jest-fetch-mock"; fetchMock.enableMocks();
Auto mocking offers a balance between ease of use and control, making it a popular choice for many developers.
Importance of Mock Fetch Request in Jest
Mock fetch requests in Jest are crucial for effective API testing. Some major reasons for their importance are listed below :
- Faster test execution by simulating API calls instead of making actual network requests. Simulating API calls rather than real network requests accelerates general development speed.
- Mocking lets developers replicate different API responses—including success cases, errors, and edge cases—without depending on third-party tools or changed server states.
- Real API endpoints might return varying data, hence tests are somewhat unreliable. Mocked answers guarantee stable test results independent of external factors or data changes.
- Working on and testing API-dependent features offline allows developers to do so without an active internet connection or access to the real API endpoints.
- By avoiding real API calls during testing, developers prevent unnecessary load on production or staging servers, which is especially important for frequently run automated tests.
Use Cases of Mock Fetch Request in Jest
When testing components that make API calls without actually hitting the server, Jest’s fetch request mocking is critical. This method eliminates reliance on third-party resources during development and enables predictable testing.
Some common use cases are –
1. Testing API Integration:
It is possible to verify if functions or components interact with an API successfully by mocking fetch requests. Verifying that the correct endpoint is called and that the data is manipulated as intended becomes much easier using this method.
test('fetches data from an API endpoint', async () => { const mockData = { id: 1, name: 'Example' }; jest.spyOn(global, 'fetch').mockResolvedValueOnce({ json: async () => mockData, }); const data = await fetchDataFromApi('/example'); expect(data).toEqual(mockData); expect(fetch).toHaveBeenCalledWith('/example'); });
2. Handling Error Responses:
Applications must be able to gracefully handle server problems or network outages. To test error-handling algorithms, mock fetch requests might mimic error conditions.
test('handles error responses gracefully', async () => { jest.spyOn(global, 'fetch').mockRejectedValueOnce(new Error('API Error')); await expect(fetchDataFromApi('/invalid')).rejects.toThrow('API Error'); expect(fetch).toHaveBeenCalledWith('/invalid'); });
3. Simulating Different API States:
Applications frequently have to deal with various API responses, including failure, success, and empty data. These different states can be simulated by mocking fetch requests, which will guarantee that the application operates as intended in every situation.
test('simulates different API response scenarios', async () => { jest.spyOn(global, 'fetch') .mockResolvedValueOnce({ json: async () => ({ success: true }) }) .mockResolvedValueOnce({ json: async () => ({ success: false }) }); const firstResult = await fetchDataFromApi('/first'); const secondResult = await fetchDataFromApi('/second'); expect(firstResult.success).toBe(true); expect(secondResult.success).toBe(false); });
4. Testing Component Behavior:
Mocking fetch requests for React components that call APIs assists in ensuring that the component appropriately updates the user interface in response to the API response. This guarantees that error messages, loading states, and data rendering all work as intended.
it('displays data fetched from API', async () => { const mockData = { id: 1, name: 'Mocked Data' }; jest.spyOn(global, 'fetch').mockResolvedValueOnce({ json: async () => mockData, }); const { getByText, findByText } = render(<ExampleComponent />); // Wait for component to render with fetched data const dataElement = await findByText('Mocked Data'); expect(dataElement).toBeInTheDocument(); expect(fetch).toHaveBeenCalledWith('/api/data'); });
How to Mock Fetch Requests in Jest?
To mock fetch requests in Jest, use jest.fn() to mock the global fetch function, returning a resolved or rejected Promise. You can then define mock responses and assert calls using expect(fetch).toHaveBeenCalledTimes().
Pre-requisites
Before getting started, make sure the following are set up:
- Node.js and NPM installed
- Jest testing framework installed
- React Testing Library (optional, for testing React components)
To install Jest and React Testing Library, use:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
The example scenario is a React component that fetches user data from an API and displays the user’s name. This component starts by showing “Loading…” and then makes an API call to get user data. Once the data is fetched, it displays the user’s name.
// UserComponent.js import React, { useEffect, useState } from 'react'; const UserComponent = () => { const [user, setUser] = useState(null); useEffect(() => { const fetchUser = async () => { const response = await fetch('https://api.example.com/user/1'); const data = await response.json(); setUser(data); }; fetchUser(); }, []); return ( <div> {user ? <h1>{user.name}</h1> : <p>Loading...</p>} </div> ); }; export default UserComponent;
Steps to Mock Fetch Requests in Jest for API Testing
Step 1: Setup the Test Environment
We must ensure Jest is aware of fetch by configuring jest.setup.js:
// jest.setup.js require('whatwg-fetch');
In package.json, include:
"jest": { "setupFilesAfterEnv": ["<rootDir>/jest.setup.js"] }
This ensures that tests have access to the fetch function and can simulate API calls.
Step 2: Mock the Fetch Request
Jest provides different ways to mock global objects, including fetch. The most common approach is to use jest.spyOn() or overriding the global fetch method.
// UserComponent.test.js import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import UserComponent from './UserComponent'; describe('UserComponent', () => { beforeEach(() => { // Clear all mocks before each test jest.clearAllMocks(); }); it('displays user name after fetching data', async () => { // Arrange: Mock the fetch request const mockUserData = { name: 'John Doe' }; jest.spyOn(global, 'fetch').mockResolvedValueOnce({ json: async () => mockUserData, }); // Act: Render the component render(<UserComponent />); // Assert: Check if Loading is displayed initially expect(screen.getByText('Loading...')).toBeInTheDocument(); // Wait for the user name to appear await waitFor(() => { expect(screen.getByText('John Doe')).toBeInTheDocument(); }); // Ensure fetch was called with the correct URL expect(fetch).toHaveBeenCalledWith('https://api.example.com/user/1'); }); });
In this test, jest.spyOn(global, ‘fetch’) is used to mimic the fetch function.mockResolvedValueOnce() makes this fake fetch return the required data. By controlling the response, the test can verify that the component correctly displays the user’s name. The render (<UserComponent />) function displays the component on a virtual screen for testing, and waitFor() ensures the test waits for the component to finish updating before checking the result.
Without actually accessing the API, this method verifies that the component operates as intended.
Step 3: Test Error Handling
To ensure the component can handle failed requests, testers can mock an error scenario as
it('handles fetch error gracefully', async () => { // Arrange: Pretend the API call fails jest.spyOn(global, 'fetch').mockRejectedValueOnce(new Error('API Error')); // Act: Render the component render(<UserComponent />); // Assert: Check if Loading is shown first expect(screen.getByText('Loading...')).toBeInTheDocument(); // Wait and check that no user name is displayed due to the error await waitFor(() => { expect(screen.queryByText('John Doe')).not.toBeInTheDocument(); }); // Confirm the component tried to call the correct API URL expect(fetch).toHaveBeenCalledWith('https://api.example.com/user/1'); });
This test uses mockRejectedValueOnce() to make the fake fetch throw an error. It ensures the component handles the error smoothly without crashing. When the API call fails, queryByText() is used to verify that the user name is not displayed. This validates the error-handling mechanism of the component.
Step 4: Run the Tests
Use the command below to run the tests:
npx jest UserComponent.test.js
Or, if React scripts are being used:
npm test
Best Practices to mock fetch requests in Jest
- Make use of a dedicated library: Use libraries such as jest-fetch-mock to provide more control over fetch calls and streamline the mocking process.
- Create helper functions: To make tests easier to comprehend and manage, develop reusable helper functions that generate mock replies.
- Mock both success and error cases: Make sure the tests cover a range of situations by simulating both error conditions and successful API requests.
- Clean up after every test: To avoid test pollution, use afterEach hooks to reset the fetch implementation and remove mocks.
- Isolate tests: Instead of using global mocks for all tests, fake fetch calls unique to each test case to keep your tests focused and isolated.
Conclusion
For reliable and effective API testing, it is imperative to become proficient with Jest’s mock fetch requests. Developers can guarantee consistent, quick, and dependable testing by employing manual or auto-mocking procedures.
To further enhance testing, consider integrating with tools like BrowserStack Test Observability, which provides deeper insights into your test runs. Additionally, testing Jest suites on real devices using BrowserStack ensures compatibility and optimal performance across various environments, leading to higher quality web applications.