Basic Setup
-
Install the testing library for hooks:
npm install @testing-library/react-hooks
Note: This library provides utilities to test custom React hooks effectively.
-
Import
renderHook
andact
in your test file:import { renderHook, act } from "@testing-library/react-hooks";
Tip:
act
is essential for ensuring that all updates related to state and effects are processed correctly.
Basic Usage
-
Testing a simple hook:
const { result } = renderHook(() => useCustomHook()); expect(result.current.someValue).toBe(initialValue);
Detail:
result.current
gives you access to the current state of the hook.
Updating Hook State
-
When the hook involves state updates, use
act
:const { result } = renderHook(() => useCounter()); act(() => { result.current.increment(); }); expect(result.current.count).toBe(1);
Best Practice: Always wrap state updates in
act
to ensure proper state management.
Testing with Props
-
Pass props to the hook and update them:
const { result, rerender } = renderHook(({ value }) => useCustomHook(value), { initialProps: { value: 0 }, }); expect(result.current.value).toBe(0); // Update the prop rerender({ value: 1 }); expect(result.current.value).toBe(1);
Tip: Use
rerender
to simulate prop changes and test how the hook responds.
Testing Async Hooks
-
Handling asynchronous code with hooks:
const { result, waitForNextUpdate } = renderHook(() => useAsyncHook()); expect(result.current.loading).toBe(true); // Wait for the next state update await waitForNextUpdate(); expect(result.current.loading).toBe(false); expect(result.current.data).toEqual(expectedData);
Detail:
waitForNextUpdate
is crucial for testing hooks that perform asynchronous operations.
Using waitFor
-
For hooks that might update multiple times:
import { waitFor } from "@testing-library/react"; const { result } = renderHook(() => useDebouncedValue(input)); await waitFor(() => { expect(result.current).toBe(expectedValue); });
Note:
waitFor
allows you to wait for a specific condition to be met, which is useful for debounced values.
Cleaning Up After Tests
-
To ensure proper cleanup between tests:
afterEach(() => { // Clean up any effects left behind cleanup(); });
Best Practice: Always clean up after tests to prevent side effects from affecting other tests.
Mocking External Dependencies
-
Example with
jest.mock
:jest.mock("some-external-library", () => ({ someFunction: jest.fn().mockReturnValue(mockValue), }));
Tip: Mocking external dependencies helps isolate your tests and avoid side effects from real implementations.
Summary of Methods
- renderHook: Render a hook function and return an object containing the result and helper methods.
- act: Wrap state updates to ensure React’s state batching works correctly.
- rerender: Re-render the hook with new props.
- waitForNextUpdate: Wait for the next state update.
- waitFor: Wait for a condition to be met.