how to assert that your custom hook didn’t throw

This micro blog entry is for those who:

  1. use renderHook from @testing-library/react-hooks to test their own custom hooks
  2. want to assert that the custom hook did not throw

So, by instinct, one probably would do sth along this line:

// HEADS UP: WRONG APPROACH, DO NOT APPLY TO YOUR WORK

import { renderHook } from '@testing-library/react-hooks'
import { myCustomHook } from './my-custom-hook'

it('should work', () => {
  // no, sadly this doesn't work, mate
  expect(() => renderHook(() => myCustomHook())).not.toThrow()
})

The reason why the above approach doesn’t work is quite obvious, if you think about it. You were expecting the renderHook function to not throw, and _not_ your actual custom hook. The test target has been wrong from the 1st place.

But then what should we do? In expect(<something>).not.toThrow(), the <something> has to be a function, so if we don’t pass the function that calls renderHook in there, how else do we invoke the custom hook?

The answer lies in the result of renderHook. Turns out if we use this library function, we’re well covered.. more than we expected 😉 The code speaks for itself:

// now this is a working approach
// you're safe to copy & paste 😉

it('should work', () => {
  const { result } = renderHook(() => myCustomHook())
  expect(result.error).toBeUndefined()
})

As you see there, renderHook returns to us quite a few interesting objects, one of which is named result. Inspecting result.error allows us to check if there was any error thrown during the invocation of our custom hook. Simple as that.

This goes without saying, if we wish to do the other way around e.g. assert that our custom hook _did_ throw an error, then we could do something along this line:

expect(result.error.message).toBe('noooooooo!')

Anyway, you know your error best 😉 So, turn the above to whatever form that works best for your use case.

Bonus: as hinted above, besides result, renderHook gives us a number of other very useful controls. Discussing them is beyond the scope of this blog entry, and I’ll leave them as a bonus “take-home material” 🙂

Cheers,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s