0
0
ReactHow-ToBeginner · 4 min read

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 act can cause warnings and unreliable tests.
  • Trying to test hooks by calling them directly outside of renderHook will 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 renderHook to run hooks in tests.
  • Wrap state changes in act to avoid warnings.
  • Check result.current for 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.