React Hooks Wrapper not getting updated after state change in useEffect

Viewed 1109

Current behaviour

I'm using a functional component with a setState hook in useEffect. The state variable that is set inside useEffect is wrapped over the return statement to render the JSX for the component.

When I debug into it, the component renders with the correct state variable but my wrapper in my test does Not show the correct information.

wrapper.update() isn't fixing this issue.

Below is a snippet of what I am trying to achieve:

const DummyComponent= ({}) => {
    const [selected, setSelected] = React.useState(false);

    useEffect(() => {
      setSelected(true)
    }, [someDependency])

    return (
      { 
         selected && (
         <div id= 'container'>
            {childComponents}
          </div>)
       }
    );
    })

it('test', () => {
     const wrapper= mount( <DummyComponent  /> ); 
    wrapper = wrapper.update(); // this doesn't fix my problem   
    wrapper.find('#container')first().props().onClick();
    expect(wrapper.toMatchSnapshot());
});

I am getting the below error:

Method “props” is meant to be run on 1 node. 0 found instead.

Expected Behaviour

After state update in useEffect re-render should be triggered in test case and element with id="container" should be found.

Note: This is not same as https://github.com/enzymejs/enzyme/issues/2305

 

3 Answers

It seems to me there's some other problem with your real code (maybe some promise-based code invoked in the effect?). Here's a working example based on your snippet:

const DummyComponent = ({}) => {
    const [selected, setSelected] = React.useState(false);
    const [result, setResult] = React.useState("");

    React.useEffect(() => {
        setSelected(true);
    }, []);

    return selected && <div id='container' onClick={() => setResult("test")}>
        <label>{result}</label>
    </div>;
};

it('test', () => {
    const wrapper = mount(<DummyComponent/>);
    act(() => {
        wrapper.find('#container').first().props().onClick();
    });
    expect(wrapper.find("label").text()).toEqual("test");
});

The act is actually needed only for interaction with the component itself, not for after-render effect.

The problem is that when you first mount the component, it does not render anything, because selected is false. So, when you search for '#container', you don't get anything.

If the update is enough, then it should probably be executed before the wrapper.find(), so that the component is rendered with selected true. But React is asynchronous and I suspect that this will not be enough…

I fixed my problem, actually I need to assign my component to a different wrapper and then update the wrapper and then check for updates on the wrapper instead of the component. Below is the snippet:

it('test', () => {

     const component= mount( <DummyComponent  /> ); 
     const wrapper = component.update();  
     wrapper.find('#container')first().props().onClick();
     expect(wrapper.toMatchSnapshot());

}); 

This will have the updated component

Related