HomeAbout Me

React Testing 8: Testing custom hook

By Daniel Nguyen
Published in React JS
September 09, 2024
1 min read
React Testing 8: Testing custom hook

testing custom hooks

Background

Testing custom hooks is a common question as well. Step back and think about how our guiding testing principle applies to this situation: the more your tests resemble the way your software is used, the more confidence they can give you. How is your custom hook used? It’s used in a component! So that’s how it should be tested.

Often, the easiest and most straightforward way to test a custom hook is to create a component that uses it and then test that component instead.

Exercise

In this exercise, we have gone back to our simple counter, except now that logic is all in a custom hook and we need to test that functionality. To do that, we’ll make a test component that uses the hook in the typical way that our hook will be used and then test that component, indirectly testing our hook.

Extra Credit

1. 💯 fake component

Sometimes it’s hard to write a test component without making a pretty complicated “TestComponent.” For those situations, you can try something like this:

let result
function TestComponent(props) {
result = useCustomHook(props)
return null
}
// interact with and assert on results here

Learn more about this approach from my blog post: How to test custom React hooks

2. 💯 setup function

Add tests titled:

  1. allows customization of the initial count
  2. allows customization of the step

And test those use cases. Then abstract away the common logic into a setup function. This one might be a little tricky thanks to variable references, but I know you can do it!

💰 Here’s a little tip. Due to variable references, you’ll need to change your test component a bit:

const results = {}
function TestComponent(props) {
Object.assign(results, useCustomHook())
return null
}
// interact with and assert on results here

3. 💯 using react-hooks testing library

Your setup function is very similar to the renderHook function from @testing-library/react! Swap your own setup function with that!

NOTE: Originally this exercise used @testing-library/react-hooks which was similar, but that functionality was merged directly into @testing-library/react so you’re going to use that instead.

🦉 Elaboration and Feedback

After the instruction, if you want to remember what you’ve just learned, then fill out the elaboration and feedback form:

https://ws.kcd.im/?ws=Testing%20React%20Applications%20%F0%9F%A7%90&e=08%3A%20testing%20custom%20hooks&em=

Resources

Step back and think about how our guiding testing principle applies to this situation: the more your tests resemble the way your software is used, the more confidence they can give you. How is your custom hook used? It’s used in a component! So that’s how it should be tested.

import * as React from 'react'
function useCounter({initialCount = 0, step = 1} = {}) {
const [count, setCount] = React.useState(initialCount)
const increment = () => setCount(c => c + step)
const decrement = () => setCount(c => c - step)
return {count, increment, decrement}
}
export default useCounter
import {renderHook, act} from '@testing-library/react'
import useCounter from '../../components/use-counter'
test('exposes the count and increment/decrement functions', () => {
const {result} = renderHook(useCounter)
expect(result.current.count).toBe(0)
act(() => result.current.increment())
expect(result.current.count).toBe(1)
act(() => result.current.decrement())
expect(result.current.count).toBe(0)
})
test('allows customization of the initial count', () => {
const {result} = renderHook(useCounter, {initialProps: {initialCount: 3}})
expect(result.current.count).toBe(3)
})
test('allows customization of the step', () => {
const {result} = renderHook(useCounter, {initialProps: {step: 2}})
expect(result.current.count).toBe(0)
act(() => result.current.increment())
expect(result.current.count).toBe(2)
act(() => result.current.decrement())
expect(result.current.count).toBe(0)
})
test('the step can be changed', () => {
const {result, rerender} = renderHook(useCounter, {
initialProps: {step: 3},
})
expect(result.current.count).toBe(0)
act(() => result.current.increment())
expect(result.current.count).toBe(3)
rerender({step: 2})
act(() => result.current.decrement())
expect(result.current.count).toBe(1)
})

Tags

#React

Share

Previous Article
The development of travel under the ocean

Related Posts

🚀 Setting Up a React Project with Vite
September 25, 2024
1 min
© 2025, All Rights Reserved.
Powered By

Quick Links

About Me

Legal Stuff

Social Media