Unit testing a custom hook with renderHook
knowing how to test hook logic in isolation.
render the hook, read result.current, fire actions inside act, assert updated state.
calling hook directly outside a component or skipping act around updates.
WHAT THIS TESTS The interviewer wants to see that you can test stateful logic in isolation. Hooks cannot be called outside a React component, so renderHook provides a tiny host component that runs the hook and exposes its return value, letting you assert behavior without rendering UI.
A GOOD ANSWER COVERS You call renderHook with a callback that returns the hook, for example const { result } = renderHook(() => useCounter()). The current return value lives on result.current, so you first assert the initial count. To trigger a state change you call the exposed function inside act, like act(() => result.current.increment()), because state updates must be flushed before you read them. Then assert result.current.count equals the expected value. You should test the initial state, an increment, a decrement, and any boundary such as not going below zero if the hook enforces that.
COMMON WRONG ANSWERS Calling useCounter() directly in the test body throws because hooks require a React render context. Reading result.current after dispatching without wrapping in act produces a stale value and a console warning. Snapshotting the hook or asserting on internal useState calls couples the test to implementation instead of behavior.
LIKELY FOLLOW-UPS How do you test a hook that takes props and re-renders with new ones? Use the rerender function from renderHook and pass initialProps. How do you test async hooks? Use waitFor or the async act and await state settling. How do you test a hook that depends on context? Pass a wrapper option that provides the context.
ONE CONCRETE EXAMPLE import { renderHook, act } from '@testing-library/react-native'. const { result } = renderHook(() => useCounter(0)). expect(result.current.count).toBe(0). act(() => result.current.increment()). expect(result.current.count).toBe(1). act(() => result.current.decrement()). expect(result.current.count).toBe(0). This proves the hook starts at zero and moves in both directions correctly.
Read the original → oss.callstack.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.