When testing components that use React Hooks, the goal is to ensure they behave correctly across renders, state changes, and side effects. You can use Jest and React Testing Library (RTL) to write effective tests.
For components that use useState
, useEffect
, or other Hooks, test their behavior, not implementation details.
useState
in a Counter Componentimport { render, screen, fireEvent } from "@testing-library/react";
import Counter from "./Counter"; // Component using useState
test("increments counter on button click", () => {
render(<Counter />);
const button = screen.getByText("Count: 0");
fireEvent.click(button);
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});
render()
.fireEvent.click()
.useEffect
Side Effects (API Calls)For components that fetch data inside useEffect
, mock API calls using Jest.
useEffect
import { render, screen, waitFor } from "@testing-library/react";
import axios from "axios";
import Users from "./Users"; // Fetches users from API
jest.mock("axios");
test("fetches and displays users", async () => {
axios.get.mockResolvedValue({ data: [{ name: "Alice" }] });
render(<Users />);
expect(screen.getByText(/Loading/i)).toBeInTheDocument();
// Wait for async data to load
await waitFor(() => screen.getByText("Alice"));
expect(screen.getByText("Alice")).toBeInTheDocument();
});
jest.mock()
.waitFor()
to wait for async updates.For testing standalone Hooks, use the renderHook
utility from @testing-library/react-hooks
.
useCounter
Hookimport { renderHook, act } from "@testing-library/react";
import { useCounter } from "./useCounter";
test("increments counter", () => {
const { result } = renderHook(() => useCounter());
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});
renderHook()
to call the Hook.act()
to simulate state updates.Hook Used | Testing Approach |
---|---|
useState |
Simulate user events, check UI updates |
useEffect |
Mock API calls, use waitFor() |
useContext |
Wrap component in context provider |
useReducer |
Dispatch actions, verify state changes |
useCustomHook |
Use renderHook() , trigger updates with act() |