How to Test Your First React Hook Using Testing Library

In previous posts we learned:

In this post, we're going to write tests for a custom React hook.

What We're Going to Test#

We're going to create a custom hook that will uppercase a given text string. This hook will be connected to an input and whenever a user changes the input value this hook will automatically uppercase the value.

Let's write the hook. Create a file called useUppercase.ts

In this file, we create a custom hook function useUppercase(). It accepts a string as an initial argument. We transform this string using .toUpperCase() and then store the result value in a local state.

Also, we create a function update(). This function will be a part of the public API. With this function, components will be able to update the current value.

Finally, we use useEffect() to re-render the hook if the initialValue gets changed. This, for example, happens when the component gets new props and passes the new initial value to the hook. In this case, we need to update the local state with the new value from the component.

Now, let's test the hook!

Testing Values#

To test hooks, we're going to use React Hooks Testing Library. It gives us utilities for testing hooks without even rendering a single component.

Let's install it:

Now, we create a file useUppercase.test.ts. In this file, we import our hook and describe our first test:

The first thing we want to test is that the hook returns a given initial value in the upper case.

With React Hooks Testing Library, we don't need to render a whole component, instead, we render the hook itself with a special function called renderHook():

The renderHook() function returns an object with the result field. We can access the current render result with the current field. It contains the object our hook returns. We can use autosuggestions to select a field to test against:

The coolest feature is readability. We don't need to create extra infrastructure code to test hooks in isolation. It just works!

Testing Callbacks#

Another thing we want to test is that when we call update with a new string, the hook's value updates. Let's write another test:

The current render result contains a reference to our update() method, so we can use it to simulate a change.

Notice that we need to use act(). It is required for the hook to update the values inside of it. According to the documentation:

This utility simulates how our hook will act in a browser, allowing us to update the values within it.

Testing Re-renders#

The last thing to cover is a case when the hook gets a new initialValue. In this case, we need to update its values and re-render the component that is using them.

In this test, we access not only the result but also the rerender() method. This method renders the hook with another initial value.

Also, this time we use props to pass initial values. They help us to keep the code shorter and more readable.

In general, we pass the initialProps object to options of the render() method. When we need to re-render the hook, we can pass updated values for this object.

The library infers the type of the object so we can use autosuggestions here as well:

Sources#