renderHook() renders a custom hook inside a minimal, invisible test component internally, giving direct access to whatever the hook returns via result.current, without needing to build and render a full, separate real component just to exercise that hook's logic. Since calling a hook's returned functions, like a setter or a custom action, typically causes React state updates, and therefore a re-render, those specific calls need to be wrapped in the act() utility, which ensures all resulting updates are fully applied and flushed before the test's subsequent assertions run against the hook's updated result.current value.
1Understanding How to Perform Hooks Testing in React
renderHook() renders a custom hook inside a minimal, invisible test component internally, giving direct access to whatever the hook returns via result.current, without needing to build and render a full, separate real component just to exercise that hook's logic. Since calling a hook's returned functions, like a setter or a custom action, typically causes React state updates, and therefore a re-render, those specific calls need to be wrapped in the act() utility, which ensures all resulting updates are fully applied and flushed before the test's subsequent assertions run against the hook's updated result.current value.
Wrap any call to a function returned by a tested hook, like a state setter, in act() — forgetting to do so produces a React warning about state updates not being wrapped in act(), and can lead to assertions checking a stale value before the update has actually been applied.
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('useCounter starts at 0 and increments', () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});2Practical Example
Here is a real-world application of How to Perform Hooks Testing in React showing how it is used in production React code.
import { renderHook } from '@testing-library/react';
import { useCounter } from './useCounter';
test('useCounter accepts a custom initial value', () => {
const { result } = renderHook(() => useCounter(10));
expect(result.current.count).toBe(10);
});3Best Practices
Follow these guidelines when working with How to Perform Hooks Testing in React:
1. Use renderHook() to test a custom hook's logic in isolation, rather than needing to build a full component solely to exercise that hook
2. Wrap calls to any function returned by the hook, like a setter or an action, in act(), ensuring the resulting update is fully applied before asserting against result.current
3. Focus hook tests on the hook's actual returned values and behavior across different inputs, rather than any specific component that might eventually consume it
Tip: Wrap any call to a function returned by a tested hook, like a state setter, in act() — forgetting to do so produces a React warning about state updates not being wrapped in act(), and can lead to assertions checking a stale value before the update has actually been applied.
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('useCounter starts at 0 and increments', () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});