All topics
Testingintermediate

Testing Custom Hooks

Learn how to test custom hooks in isolation using renderHook without needing a full component to host them.

Custom hooks can't be called outside of a React component's render, which means testing one directly by simply invoking it as a plain function fails — it needs to run inside React's rendering machinery to correctly manage its internal hook state. Testing Library provides renderHook (from @testing-library/react) specifically to solve this: it mounts a minimal, invisible test component that calls your hook and exposes its return value for assertions.

renderHook is like a minimal test rig that plugs your engine (the custom hook) into just enough of a car chassis (a bare test component) to actually start it up and observe its readings, without needing to build and drive a fully finished vehicle (a real, complete UI component) just to verify the engine runs correctly.

Key Concepts

1
renderHook(() => useMyHook(args)) returns a result object whose .current property reflects the hook's latest return value; calling functions returned by the hook (like a setter) needs to be wrapped in act() (or use Testing Library's act-wrapped helpers) so React properly flushes the resulting state update and re-render before your assertion reads result.current again.
renderHook(() => useMyHook(args))result.currentact()act
2
For hooks involving asynchronous behavior (an effect that fetches data, or a debounced value), waitFor (or findBy*-style async utilities) lets a test wait for the hook's state to settle into an expected value rather than asserting immediately after a synchronous action, since the relevant update may only become visible after a promise resolves or a timer fires.
waitForfindBy*
3
Interviewers ask candidates to write a test for a custom hook like useCounter or useDebouncedValue, checking that they correctly use renderHook, properly wrap state-updating calls in act, and use waitFor appropriately for any asynchronous behavior the hook exposes, rather than trying to test the hook by extracting and calling it as a bare function.
useCounteruseDebouncedValuerenderHookactwaitFor