React | Write a unit test for custom hooks in ten minutes
Hello guys! I am Clark! I am going to sharing how to write a unit test for custom hooks!
Custom Hooks
Before we write the first unit test, we should have a custom hooks first. If you don’t understand what is the custom hooks, I recommend you can read the official document about custom hooks first, or if you already known what is the custom hooks, you can continue to read:
import { useState, useEffect } from 'react';
const useCounter = (s, cb) => {
const [count, setCount] = useState(s);
const add = (addend = 1) => {
setCount(count + addend);
};
useEffect(cb, [count]);
return { count, add };
};
export default useCounter;
Above code snippet is a custom hooks name useCounter
, the useCounter
would manage the logic about counter. The return object include a current count and method of increase current count. On the other hand, useCounter
receive two parameters, the first is the initial value of count, the second is a callback function, the callback function will execute after count changed.
So we can use useCounter
like this:
import React from 'react'
import ReactDom from 'react-dom'
import useCounter from '../hooks/useCounter';
const Main = () => {
const { count, add } = useCounter(5, () => { console.log('Here is the callBack') });
return (
<div>
<span>{count}</span>
<button onClick={() => { add(3); }}>++</button>
</div>
);
};
ReactDom.render(<Main />, document.getElementById('root'));
Let’s Test Custom Hooks
Beforehand
We would use react-hooks-testing-library write the unit test.
So the first step, we need to install react-hooks-testing-library and it dependent packages:
npm install --save-dev @testing-library/react-hooks react-test-renderer
Remainder, if you never write any unit tests, don’t forget install jest:
npm install --save-dev jest
When you installed and we can start to write unit tests! There are two methods we need to know in react-hooks-testing-library. The first is renderHook
, the second is act
:
renderHook
: TherenderHook
can render custom hook, you can operations the custom hook like in the component.act
: Theact
can execute the methods return from custom hook. For example, You can execute theadd
method ofuseCounter
throughact
.
Ok! Let’s write unit test!
Case 1
The first case is that I want to check default value of count
will be zero. The unit test doesn’t need to execute any methods so it doesn’t need to use act
, only need renderHook
:
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from '../hooks/useCounter';
describe('useCounter', () => {
test(`Default value of `count` will be zero`, () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
});
});
The renderHook
will return an object, we can get result
from the object, and result.current
is the state of custom hooks currently. So the unit test use the expect
method check the result.current.count
if to be zero.
Case 2
The second case is going to check if the add
could correct change count
:
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from '../hooks/useCounter';
describe('useCounter', () => {
/* Case 1: Default value of `count` will be zero */
test('The `add` could correct change `count`', () => {
const { result } = renderHook(() => useCounter());
act(() => { result.current.add(3); });
expect(result.current.count).toBe(3);
});
});
In the above example, The act
would received the function and execute that.
Case 3
The third case is going to check if callback function will trigger after the count
changed. In this case besides the renderHook
and act
methods, also will use the mock:
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from '../hooks/useCounter';
describe('useCounter', () => {
/* Case 1: Default value of `count` will be zero */
/* Case 2: The `add` could correct change `count` */
test(`The callBack function will trigger after add executed`, () => {
const callBack = jest.fn();
const { result } = renderHook(() => useCounter(0, callBack));
act(() => { result.current.add(); });
// useEffect will execute at begin,
// so after the add function executed, count of callback executed will become to two times.
expect(callBack.mock.calls.length).toBe(2);
});
});
I think test custom hooks is easily than test component. But please make sure your version of react, react-dom and react-test-renderer all above 16.9.0, otherwise you will get the error below:
I have created the repository, the repository include all above unit test. if you want to try more, just clone!
If the content of article have any question or you have other opinion for unit test, all welcome to comment below!