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
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!
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() 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!
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.
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: