React Testing Library provides a utility renderHook to test hooks. It injects a hook within a fake component that t created to manage the lifecycle of a component for you.
test('hook: prevents default on the first click, and does not on the second', async () => {
const { result } = await renderHook(() => useDoubleCheck())
expect(result.current.doubleCheck).toBe(false)
const mock = vi.fn()
const event = new MouseEvent('click', {
bubbles: true,
cancelable: true,
}) as unknown as React.MouseEvent<HTMLButtonElement>
act(() => result.current.getButtonProps({ onClick: mock }).onClick(event))
expect(result.current.doubleCheck).toBe(true)
expect(mock).toHaveBeenCalledOnce()
expect(event.defaultPrevented).toBe(true)
mock.mockClear()
const event2 = new MouseEvent('click', {
bubbles: true,
cancelable: true,
}) as unknown as React.MouseEvent<HTMLButtonElement>
act(() => result.current.getButtonProps({ onClick: mock }).onClick(event2))
expect(result.current.doubleCheck).toBe(true)
expect(mock).toHaveBeenCalledOnce()
expect(event2.defaultPrevented).toBe(false)
}) There’s one gotcha. When using renderHook, you have to remember to always deconstruct the object to get result property. It is because of how JS works or something.