How to Test Custom Hook in React: Simple Guide with Examples
To test a custom hook in React, use the
renderHook function from @testing-library/react-hooks to run the hook in a test environment. Use act to apply updates and check the hook's returned values or behavior with assertions.Syntax
The main tool to test custom hooks is renderHook from @testing-library/react-hooks. It runs your hook and returns an object with the current value and a rerender method.
Use act to wrap any updates or state changes to ensure React processes them correctly.
javascript
import { renderHook, act } from '@testing-library/react-hooks'; const { result, rerender, unmount } = renderHook(() => useYourCustomHook()); act(() => { // perform updates or trigger hook functions }); expect(result.current).toEqual(expectedValue);
Example
This example tests a simple custom hook useCounter that manages a count state with increment and decrement functions.
javascript
import { renderHook, act } from '@testing-library/react-hooks'; import { useState } from 'react'; function useCounter(initialValue = 0) { const [count, setCount] = useState(initialValue); const increment = () => setCount(c => c + 1); const decrement = () => setCount(c => c - 1); return { count, increment, decrement }; } test('useCounter increments and decrements count', () => { const { result } = renderHook(() => useCounter(5)); expect(result.current.count).toBe(5); act(() => { result.current.increment(); }); expect(result.current.count).toBe(6); act(() => { result.current.decrement(); result.current.decrement(); }); expect(result.current.count).toBe(4); });
Output
PASS useCounter increments and decrements count
Common Pitfalls
- Not wrapping state updates or hook calls that change state inside
actcan cause warnings and unreliable tests. - Trying to test hooks by calling them directly outside of
renderHookwill fail because hooks must run inside React function components. - Ignoring cleanup by not unmounting hooks can cause side effects in tests.
javascript
import { renderHook, act } from '@testing-library/react-hooks'; // Wrong: calling hook directly // const result = useCounter(); // This will error // Right: use renderHook const { result } = renderHook(() => useCounter()); // Wrong: updating state outside act // result.current.increment(); // Warning // Right: act(() => { result.current.increment(); });
Quick Reference
Remember these key points when testing custom hooks:
- Use
renderHookto run hooks in tests. - Wrap state changes in
actto avoid warnings. - Check
result.currentfor hook return values. - Unmount hooks if needed to clean up.
Key Takeaways
Use @testing-library/react-hooks renderHook to test custom hooks safely.
Wrap any hook state updates inside act to ensure React processes changes.
Access hook outputs via result.current for assertions.
Never call hooks directly outside renderHook in tests.
Clean up by unmounting hooks when necessary to avoid side effects.