Enzyme: Functional component and useState hooks - wrapper not reflecting changes after rerender triggered by setState

Created on 9 Dec 2019  路  11Comments  路  Source: enzymejs/enzyme

Current behavior

I'm using a functional component with a setState hook. I am calling a function in the component that uses that setState hook's setter function. The state variable that is set is used in the return of the functional component to pass something to a child component.

When I debug into it, the component renders with the correct state variable and the child component having the correct props But my wrapper in my test does Not show the correct information is being passed to the child component.

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

Here's a quick basic watered down example of what i am doing (component and test)

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

    function handleOnSomething(idx) {
      setSelected(idx)
   }

    return (
      <div>
        <item onSomething={handleOnSomething} isSelected={selected === 0}/>
        <item onSomething={handleOnSomething} isSelected={selected === 1}/>
      </div>
  );
})

it('test', () => {
    const wrapper= shallow(<wrapper  />);    
    wrapper.find('selector2ndItem').prop('onSomething')(1); // this method calls the setter

    wrapper.update(); // this doesnt fix my problem

    const item2 = viewer.find(selector2ndItem);

    // should be correct and is when debugging but wrapper doesn't have the changes 
    expect(item2.props().isSelected).toEqual(true); // isSelected still === false
});

Basically the test should set the 2nd item's isSelected to true. It does in the code when I debug, but the wrapper in the test doesn't show those changes.

Expected behavior

I expect item2 isSelected to equal true. When I debug into the code I see the rerender after 'setSelected' is called and it renders with the correctly selected item. In the test I cant see that though. When I do wrapper.debug() it show the old information

Your environment

Windows 10
visual studio code

API

  • [x] shallow
  • [ ] mount
  • [ ] render

Version

| library | version
| ------------------- | -------
| enzyme | ^3.3.0
| react | ^16.2.0
| react-dom | ^16.2.0
| react-test-renderer | ^16.2.0
| adapter (below) |

All enzyme stuff in my package.json
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-react-intl": "^1.4.8",
"enzyme-redux": "^0.2.1",
"enzyme-to-json": "^3.3.3",

React Intl:
"react-intl": "^2.3.0",

Adapter

  • [X] enzyme-adapter-react-16
  • [ ] enzyme-adapter-react-16.3
  • [ ] enzyme-adapter-react-16.2
  • [ ] enzyme-adapter-react-16.1
  • [ ] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )
help wanted

Most helpful comment

I got to this issue and after trying some variants, I think this one solved the problem. The key I think is in updating the wrapper after the update: wrapper = wrapper.update(), and then find the element again. The test code:

  test('canGoNext should be false initially and true when key has length = 8', () => {
    let wrapper = mountWrapper();
    let wizard = wrapper.find(Wizard);

    expect(wizard.props().canGoNext).toBeFalsy();

    const signKey = wrapper.find(SignatureKeyInput);
    act(() => {
      signKey.props().onChange('12345678');
    });
    wrapper = wrapper.update();
    wizard = wrapper.find(Wizard);
    expect(wizard.props().canGoNext).toBeTruthy();
  });

All 11 comments

I'm having the same issue

Is there any movement on this?

I'm seeing the same issue with [email protected] and [email protected].

As things stand I can't use React hooks with enzyme.

Note mount seems to work.

for unknown reason invoke() or simulate() may work well when props(...)() call does not update wrapper. Honestly did not catch any specific conditions, but it happens not to all my components.

Upgrading to [email protected] fixed the issue.

@josh08h Same issue on react 16.13.1

@makr28 what is viewer? And have you tried changing wrapper to Wrapper? Idk if it matters anymore, but in the past I've seen react treat lowercased things as dom elements and not components

This seems to work for me in a code sandbox https://codesandbox.io/s/eloquent-violet-x8gjh?file=/src/index.js

@bdwain "viewer" was a mistake on my part, i copied a test of ours and changed viewer to wrapper to be more generic in my question. I just forgot to change that instance to "wrapper". I haven't gotten a chance to try this. I found a different way to somewhat test what I needed for my project.

If everyone else says 16.13.1 fixed this, I'm cool with this getting closed.

@revoyrm

If everyone else says 16.13.1 fixed this, I'm cool with this getting closed.

I'm not sure anyone has said this. I'm running 16.13.1 and have this issue.

Do anyone have any update on this? 馃檹

a PR with failing test cases would be appreciated; it's much easier for me to come up with a fix from that.

I got to this issue and after trying some variants, I think this one solved the problem. The key I think is in updating the wrapper after the update: wrapper = wrapper.update(), and then find the element again. The test code:

  test('canGoNext should be false initially and true when key has length = 8', () => {
    let wrapper = mountWrapper();
    let wizard = wrapper.find(Wizard);

    expect(wizard.props().canGoNext).toBeFalsy();

    const signKey = wrapper.find(SignatureKeyInput);
    act(() => {
      signKey.props().onChange('12345678');
    });
    wrapper = wrapper.update();
    wizard = wrapper.find(Wizard);
    expect(wizard.props().canGoNext).toBeTruthy();
  });
Was this page helpful?
1 / 5 - 1 ratings