Hone logo
Hone
Problems

Testing React Hooks with Jest and TypeScript

Testing React hooks can be tricky, especially when dealing with custom hooks. This challenge focuses on implementing a robust testing strategy for custom hooks using Jest and TypeScript, ensuring your hooks behave as expected in isolation. Successfully completing this challenge will allow you to confidently test and maintain your React component logic.

Problem Description

You are tasked with creating a Jest test suite for a custom React hook called useFetch. This hook fetches data from a provided URL and manages loading and error states. The hook should:

  1. Accept a URL as an argument.
  2. Fetch data from the URL using fetch API.
  3. Return an object with the following properties:
    • data: The fetched data (initially null).
    • loading: A boolean indicating whether the data is being fetched (initially true).
    • error: An error object if an error occurred during fetching (initially null).
  4. Handle potential errors during fetching. If the fetch request fails, the error property should be updated with the error object.
  5. Set loading to false after the fetch request completes, regardless of success or failure.
  6. Update data with the parsed JSON response on successful fetch.

Your task is to write Jest tests that verify the behavior of the useFetch hook under various conditions, including successful data fetching, error handling, and initial state. You must use jest.mock to mock the fetch API to control the responses during testing.

Examples

Example 1: Successful Fetch

Input: useFetch('https://example.com/data')
Output: { data: { name: 'Example Data' }, loading: false, error: null } (after successful fetch and parsing)
Explanation: The hook successfully fetches data from the URL, parses it as JSON, sets data to the parsed value, sets loading to false, and error to null.

Example 2: Fetch Error

Input: useFetch('https://example.com/error') (mocked to return a 500 error)
Output: { data: null, loading: false, error: Error object }
Explanation: The hook attempts to fetch data, but an error occurs. The hook sets loading to false and error to the error object.

Example 3: Initial State

Input: useFetch('https://example.com/data') (before fetch)
Output: { data: null, loading: true, error: null }
Explanation: Before the fetch request is initiated, the hook should return an initial state with data as null, loading as true, and error as null.

Constraints

  • You must use Jest and TypeScript.
  • You must mock the fetch API using jest.mock.
  • The tests should cover the following scenarios:
    • Successful data fetching.
    • Error handling during fetching.
    • Initial state of the hook.
  • The useFetch hook implementation is provided below. Do not modify the hook itself. Only write the tests.
  • Assume the URL will always be a string.

Notes

  • Consider using async/await for cleaner asynchronous testing.
  • Pay close attention to the order in which the state variables are updated.
  • Think about how to effectively mock the fetch API to simulate different scenarios.
  • The useFetch hook is provided below for reference.
import { useState, useEffect } from 'react';

function useFetch(url: string) {
  const [data, setData] = useState<any>(null);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<any>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
      } catch (e: any) {
        setError(e);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;
Loading editor...
typescript