When writing React applications, you likely want to use Testing Library. It's a tool specifically designed to test UI components from a user's perspective, encouraging developers to write tests that simulate real user interactions. It comes with a great React integration.
The renderHook
function is a utility that allows you to test custom hooks. It provides a way to render a custom hook in a testing environment and access the values it returns. renderHook
sets up the necessary infrastructure to execute the hook and provides an API to interact with its state and effects, enabling comprehensive testing of the hook's behavior and functionality. It ensures that hooks are tested in isolation, making it easier to write effective unit tests for hooks without the need for rendering a full React component.
Why a hook might throw an error
Oftentimes, you want your custom hook to explicitly throw an error if something is wrong. Possible scenarios could be:
- A hook that relies on certain function arguments and throws if they are not provided correctly.
- A hook that reads the value from a React context and throws if the context provider is not present.
- A hook that depends on an external API and throws if it receives a negative response.
In such scenarios, you want to make sure the behavior works as intended, and you can use renderHook
for this purpose.
First, let's take a look at a custom hook that throws an error. It's an easy one, because it always throws.
function useSomething(){
throw new Error("something failed");
}
The following examples in this article are written for Jest, but the same concept applies to other testing frameworks like Mocha or Cypress.
The old way before React 18 β
Before the release of React 18 renderHook
was provided in a separated package called @testing-library/react-hooks. To ensure a hook throws an error, they integrated a wrapper that catches occurring errors and provides them under result.error
.
This is how you would have tested if a hook throws an error:
test('should throw an error', () => {
const { result } = renderHook(() => useSomething());
expect(result.error).toBe(Error('something failed'));
})
You call the renderHook
function and pass a callback function that calls the hook function. renderHook
returns an object included the result
of the call. In case an error was thrown, you can read result.error
. You can make an assertion in your unit test and compare it to an expected error message.
The new way with React 18 β
After the release of React 18 the authors of Testing Library decided to integrate the renderHook
utility directly into @testing-library/react
instead of maintaining a separated package for this API.
As you can read in the pull request for this change, testing errors will no longer be solved. This means you need a different approach to ensure a custom hook throws an error.
This is how you can test for thrown errors now:
test('should throw an error', () => {
expect(() => {
renderHook(() => useSomething());
}).toThrow('something failed');
});
This is pretty straightforward. It doesn't rely on any additional implementation provided by Testing Library to catch the thrown error and deal with it. Instead, the error simply escalates, and you can handle it yourself, like here with the .toThrow()
matcher.
If you feel like passing an arrow function to expect
looks a bit funny, this slightly more verbose approach also works:
test('should throw an error', () => {
try {
renderHook(() => useSomething());
}
catche(error){
expect(error).toBe('something failed')
}
});
There are quite a few other things that changed for Testing Library with the release of React 18. You can check out the migration guide for further information.
Top comments (4)
This prevents error from being shown in the console
This test will pass if
useSomething
doesn't throw an error.We can add an assertion to ensure is called at least once.
Que maneiro, e isso nΓ£o tΓ‘ muito claro na doc do @testing-library/react, deveria tΓ‘ num tΓ³pico em grande destaque.
Obrigado pelo artigo fera !
Thanks for the feedback. If you have an idea on how to improve the docs, you can go ahead an contribute to them ;-)
github.com/testing-library/testing...