How do you unit test a custom React hook like useCounter?
This tests whether you know hooks must run inside a component and that renderHook provides that scaffold. A strong answer names renderHook and act, explains result.current access, and warns against calling hooks directly.
WHAT THIS TESTS: This question probes whether you understand why hooks cannot be called outside a React component and which testing utility creates the required component boundary. It also checks if you know how to read hook results, trigger updates safely, and exercise lifecycle behavior in isolation.
A GOOD ANSWER COVERS: First, name renderHook as the essential utility exported by react-hooks-testing-library because it renders a hidden test component that invokes your hook on every render. Second, explain that result.current exposes the hook's latest return value, such as count and increment functions from useCounter. Third, state that any interaction triggering a re-render must be wrapped in act to flush effects and state updates, just like in component tests. Fourth, note that rerender lets you pass new props to test hook recalculation, and unmount lets you verify cleanup logic in useEffect return functions.
COMMON WRONG ANSWERS: Calling useCounter directly at the top level of a test violates the Rules of Hooks and will throw or behave unpredictably. Creating a one-off TestComponent inside the spec file works but is verbose and misses the point of the dedicated utility. Forgetting to wrap state changes in act produces React warnings and race conditions. Ignoring cleanup or unmount can leak subscriptions and timers between tests.
LIKELY FOLLOW-UPS: An interviewer might ask how you provide context to a hook under test, which is done via the wrapper option in renderHook. They might ask how to test asynchronous behavior, which the library handles through its dedicated async utilities. They could also ask how to test useEffect cleanup, which requires calling unmount and asserting side effects have been torn down.
ONE CONCRETE EXAMPLE: Suppose useCounter returns an object with count, increment, and decrement. You would write const { result } = renderHook(() => useCounter()). Expect result.current.count to be 0 initially. Then wrap the interaction in act like this: act(() => result.current.increment()). After act completes, expect result.current.count to be 1. If the hook accepts an initial value prop, call rerender({ initialValue: 5 }) and assert the count updates accordingly. Finally, call unmount to confirm any timers or event listeners registered in useEffect are removed.
Read the original → react-hooks-testing-library.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.