Hone logo
Hone
Problems

Mocking Network Errors in Jest for Robust API Testing

Testing asynchronous operations, especially those involving network requests, can be challenging. It's crucial to ensure your application handles network failures gracefully. This challenge focuses on how to effectively simulate network errors within your Jest tests, allowing you to verify your error handling logic.

Problem Description

Your task is to write Jest tests for a hypothetical fetchData function that makes an API call. You need to simulate a network error (e.g., a network timeout or a server unavailability) and verify that your fetchData function correctly catches and handles this error. This is essential for building resilient applications that don't crash or present a poor user experience when network issues arise.

Key Requirements:

  • Mock fetch: You will need to mock the global fetch API to control its behavior during tests.
  • Simulate Network Error: Configure your mock fetch to reject with an error, mimicking a network failure.
  • Test Error Handling: Write a Jest test that calls fetchData and asserts that the expected error is caught and handled appropriately.
  • TypeScript: Implement the solution using TypeScript.

Expected Behavior:

When fetchData is called and the underlying fetch request fails due to a network error, the fetchData function should:

  1. Reject its promise.
  2. The rejection reason should be an Error object that represents the network failure.

Edge Cases:

  • Consider what happens if the fetch call rejects with something other than a standard Error object (though for this challenge, we'll focus on simulating a standard Error).

Examples

Example 1: Simulating a Network Error

Let's assume you have a function fetchData(url: string) that uses fetch internally.

src/api.ts (hypothetical)

export async function fetchData(url: string): Promise<any> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error("Network or fetch error:", error);
    throw error; // Re-throw the error to be caught by the caller
  }
}

src/api.test.ts

// Assuming 'fetch' is mocked globally
import { fetchData } from './api';

describe('fetchData', () => {
  it('should handle network errors gracefully', async () => {
    const testUrl = 'https://example.com/api/data';
    const networkError = new Error('Network request failed');

    // Mock fetch to reject with a network error
    global.fetch = jest.fn().mockRejectedValueOnce(networkError);

    // Expect fetchData to reject with the same error
    await expect(fetchData(testUrl)).rejects.toThrow('Network request failed');

    // Optional: Verify fetch was called with the correct URL
    expect(global.fetch).toHaveBeenCalledWith(testUrl);
  });
});

Explanation:

In this example, we mock global.fetch to jest.fn().mockRejectedValueOnce(networkError). This tells Jest that the next time fetch is called, it should immediately reject with the networkError object. The expect(fetchData(testUrl)).rejects.toThrow('Network request failed'); assertion then verifies that our fetchData function correctly catches this rejection and re-throws an error that contains the expected message.

Constraints

  • TypeScript: All code, including tests, must be written in TypeScript.
  • Jest: Utilize Jest for mocking and assertions.
  • Global fetch: Assume the target function uses the global fetch API.
  • Error Type: The simulated network error should be an instance of Error.

Notes

  • You might need to set up your Jest environment to handle global types correctly if you are using a specific Node.js version or setup.
  • Consider the difference between a network error (where fetch itself rejects) and an HTTP error (where fetch resolves but the response status indicates an error, like 404 or 500). This challenge specifically focuses on simulating the former.
  • The jest.fn().mockRejectedValueOnce() is a powerful tool for simulating asynchronous rejections.
  • Use await expect(...).rejects.toThrow(...) to assert that an asynchronous function throws an error.
Loading editor...
typescript