16

I want to test the state update of the component using renderHook from @testing-library/react-hooks, which let us render the hook in the same way as we do in a react functional component. Just want to know, is this only applicable for custom hooks, because the state is not getting changed when I am trying this for testing a component

it('test count update', () => {
    const { result } = renderHook(() => useState({ count: 0 }));
    const [state, setState] = result.current;
    const wrapper = mount(<ComponentToTest />);

    act(() => {
       wrapper.find('button').simulate('click');
    })
    expect(state).toBe({ count: 1 });
})

getting an error since the count is not getting updated and still remains 0

Can anyone please help

enter image description here

1 Answer 1

25

From the docs:

Renders a test component that will call the provided callback, including any hooks it calls, every time it renders.

renderHook is used to test the hook itself, not a component that uses that hook. renderHook itself renders a test component; you cannot directly test or verify a hook's result by rendering a component that happens to use that hook.

In your case, you're just testing useState, which you can absolutely do with renderHook.

NB This is not a test that you should write for your components! It is here merely to illustrate how renderHook can be used to test any hook.

import { useState } from 'react'
import { renderHook, act } from '@testing-library/react'

it('test count update', async () => {
  const { result } = renderHook(() => useState({ count: 0 }))
  const [state, setState] = result.current
  act(() => setState({ count: state.count + 1 }))
  const [nextState, _] = result.current
  expect(nextState.count).toBe(1)
})

But that seems kind of pointless; we know useState works.

If you want to test a component that uses useState (or any hook), you need to render the component itself and assert the result of that hook in the rendered component. E.g.

it('test count update', () => {
    const wrapper = mount(<ComponentToTest />);

    act(() => {
       wrapper.find('button').simulate('click');
    })
    // assuming the result is rendered in a span with a classname of 'result'
    expect(wrapper.find('span.result').text()).toBe('1');
})
Sign up to request clarification or add additional context in comments.

6 Comments

bro, you have logic in your first test. Not good. You should be testing it as a black box, but instead you're testing the test
Indeed, that is the point I was illustrating! Testing the test does seem a bit pointless. The second code snippet is more aligned with the approach I take when testing React hooks.
the useState test does not work by the way.
Yeah, I came here looking for a working "hello world" (ie. a test of useState), and got excited when I thought I saw one, because I couldn't produce one myself. I guess the OP couldn't either :( It's also worth noting that this isn't anact issue; changing the setState line to act(() => setState({ count: state + 1 })); doesn't help (which makes sense, as I think useState has act "built-in").
For anyone else looking for it, here's a working useState test: let hook; await act(async () => { hook = renderHook(() => useState<any>({ count: 0 })); }); const { result } = hook; act(() => result.current[1]({ count: result.current[0].count + 1 })); expect(result.current[0].count).toBe(1); ... also make sure you're using the newer @testing-library/react-hooks package.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.