9/18 | Validate feature ideas earlier with AI-driven prototypes

What are best AI tools? Take the State of AI survey

Builder.io
Builder.io
Contact sales

9/18 | Validate feature ideas earlier with AI-driven prototypes

What are best AI tools? Take the State of AI survey

Builder.io
Builder.io
< Back to blog

Web Development

How to Test Custom React Hooks with React Testing Library

May 9, 2023

Written By Vishwas Gopinath

Custom React hooks offer developers the ability to extract and reuse common functionality across multiple components. However, testing these hooks can be tricky, especially if you are new to testing. In this blog post, we will explore how to test a custom React hook using React Testing Library.

Testing React components

To start, let’s review how to test a basic React component. Let's consider the example of a Counter component that displays a count and a button that increments it when clicked. The Counter component takes an optional prop called initialCount which defaults to zero if not provided. Here's the code:

To test the Counter component using React Testing Library, we follow these steps:

  1. Render the component using the render function from the React Testing Library.
  2. Get the DOM elements using the screen object from the React Testing Library. ByRole is the recommended way to query elements.
  3. Simulate user events using the @testing-library/user-event library.
  4. Assert against the rendered output.

The following tests verify the functionality of the Counter component:

The first test verifies that the Counter component renders with a count of 0 by default. In the second test, we pass in a value of 1 for the initialCount prop and test whether the rendered count value is also 1.

Finally, the third test checks whether the Counter component updates the count correctly after the increment button is clicked.

Testing custom React hooks

Now, let's look at an example of a custom hook and how we can test it using the React Testing Library. We've extracted the counter logic into a custom React hook called useCounter.

The hook accepts an initial count as an optional prop and returns an object with the current count value and the increment function. Here's the code for the useCounter hook:

Using this custom hook, we can easily add counter functionality to any component in our React application. Now, let's explore how to test it using React Testing Library.

Issues when testing custom React hooks

Testing custom React hooks is different from testing components. When you try to test the hook by passing it to the render() function, you'll receive a type error indicating that the hook cannot be assigned to a parameter of type ReactElement<any, string | JSXElementConstructor<any>>. This is because custom hooks do not return any JSX, unlike React components.

On the other hand, if you attempt to invoke the custom hook without the render() function, you'll see a console error in the terminal indicating that hooks can only be called inside function components.

Testing custom React hooks can indeed be tricky.

Testing custom hooks with renderHook()

To test custom hooks in React, we can use the renderHook() function provided by the React Testing Library. This function allows us to render a hook and access its return values. Let's see how we can update our test for the useCounter() hook to use renderHook():

In this test, we use renderHook() to render our useCounter() hook and obtain its return value using the result object. We then use expect() to verify that the initial count is 0.

Note that the value is held in result.current. Think of result as a ref for the most recently committed value.

Using options with renderHook()

We can also test whether the hook accepts and renders the same initial count by passing an options object as the second argument to renderHook():

In this test, we pass an options object with an initialCount property set to 10 to our useCounter() hook using the initialProps option of the renderHook() function. We then use expect() to verify that the count is equal to 10.

Using act() to update the state

For our last test, let’s ensure the increment functionality works as expected.

To test whether the increment functionality of the useCounter() hook works as expected, we can use renderHook() to render the hook and call result.current.increment().

However, when we run the test, it fails with an error message, "Expected count to be 1 but received 0”.

Console error: Use Counter should increment the amount. Expected 1, Received 0

The error message also provides a clue as to what went wrong: "An update to TestComponent inside a test was not wrapped in act(...)." This means that the code causing the state update, in this case the increment function, should have been wrapped in act(...).

In the React Testing Library, the act() helper function plays a vital role in ensuring that all updates made to a component are fully processed before making assertions.

Specifically, when testing code that involves state updates, it's essential to wrap that code with the act() function. This helps to simulate the behavior of the component accurately and ensure that your tests reflect real-world scenarios.

Note that act() is a helper function provided by the React Testing Library that wraps code that causes state updates. While the library typically wraps all such code in act(), this is not possible when testing custom hooks where we directly call functions that cause state updates. In such cases, we need to wrap the relevant code manually with act().

By wrapping the increment() function with act(), we ensure that any modifications to the state are applied before we perform our assertion. This approach also helps avoid potential errors that may arise due to asynchronous updates.

Conclusion

When testing custom hooks using the React Testing Library, we use the renderHook() function to render our custom hook and verify that it returns the expected values. If our custom hook accepts props, we can pass them using the initialProps option of the renderHook() function.

Additionally, we must ensure that any code that causes state updates is wrapped with the act() utility function to prevent errors. For more information on testing React applications with Jest and React Testing Library, check out my React Testing playlist.

Share

Twitter
LinkedIn
Facebook
Share this blog
Copy icon
Twitter "X" icon
LinkedIn icon
Facebook icon

Visually edit your codebase with AI

Using simple prompts or Figma-like controls.

Try it nowGet a demo

Design to Code Automation

A pragmatic guide for engineering leaders and development teams


Continue Reading
design9 MIN
How to generate (actually good) designs with AI
September 17, 2025
AI9 MIN
7 Levels of Context Engineering for Designers
September 16, 2025
Design to Code8 MIN
Git Branching for Designers
September 11, 2025

Product

Visual CMS

Theme Studio for Shopify

Sign up

Login

Featured Integrations

React

Angular

Next.js

Gatsby

Resources

User Guides

Developer Docs

Forum

Blog

Github

Get In Touch

Chat With Us

Twitter

Linkedin

Careers

© 2020 Builder.io, Inc.

Security

Privacy Policy

Terms of Service

Get the latest from Builder.io

By submitting, you agree to our Privacy Policy

  • Fusion

  • Publish

  • Product Updates

  • Design to Code

  • Headless CMS

    Multi-Brand CMS

  • Landing Pages

  • Web Apps

  • Prototypes

  • Marketing Sites

  • Headless Commerce

  • Documentation

  • Fusion Docs

  • Publish Docs

  • Blog

  • Webinars

  • Guides

  • Case Studies

  • Community Forum

  • Partners

  • Affiliate Program

  • CMS Integrations

  • CMS Blueprints

  • Glossary

  • Figma to Code Guide

  • Headless CMS Guide

  • Headless Commerce Guide

  • Composable DXP Guide

  • About

  • Careers

  • Contact Sales

Security

Privacy Policy

SaaS Terms

Compliance

Cookie Preferences

YouTube icon
Github icon
Blsky Icon
Twitter "X" icon
LinkedIn icon
Feed Icon
Gartner Cool Vendor 2024