enzyme: wrapper is not updated when using conditional rendering in v3

I found that when using conditional rendering, after setProps, wrapper is not updated properly.

// src/Hello.js
import React from 'react';

export default ({ show }) => (
  <div>
    {show ? <span>hello</span> : null}
  </div>
);
// tests/Hello.test.js
import { mount } from 'enzyme';
import React from 'react';
import Hello from '../src/Hello';

test('Hello', () => {
  const wrapper = mount(<Hello show />)

  expect(wrapper.find('span').length).toBe(1)

  wrapper.setProps({ show: false });
  expect(wrapper.find('span').length).toBe(0)

  wrapper.setProps({ show: true });
  wrapper.update(); // even though calling wrapper.update explicitly
  console.log(wrapper.debug()); // no span
  console.log(wrapper.html()); // has span
  expect(wrapper.find('span').length).toBe(1) // failed
});

Here is a reproduction repo https://github.com/yesmeck/enzyme-set-props-bug

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 27
  • Comments: 36 (14 by maintainers)

Most upvoted comments

Having this issue too, conditional rendering doesn’t happen on a component I mounted.

Both wrapper.update() and wrapper.instance().forceUpdate() don’t help either.

"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "3.3.4",
"react": "16.4.1",

Can confirm, having the same issue with React 16 and Enzyme 3, .html() yields correct result but using .debug() or trying to .find(‘selector’) will yield no result after conditional rendering.

@neoziro Thank you for taking the time to fix this. Do you have any idea when this change will be published on npm so we can upgrade? 😃

I can confirm this is still an issue. "enzyme": "3.3.0", "enzyme-adapter-react-16": "1.1.1",

I investigated it and found the source of the bug:

https://github.com/airbnb/enzyme/blob/master/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js#L66

At the first render, vnode.memoizedProps is the source of truth. At the second, vnode.alternate.memoizedProps is the source of truth. At the third, vnode.memoizedProps is the source of truth.

That was it is named alternate I think. We should confirm this from the React team and ask them the correct way to handle it.

Should we alternate the node at each render? @gaearon @sebmarkbage @acdlite

@sebmarkbage thanks for the context, that’s really helpful! i will work on rewriting this. hopefully we can get some cleaner code doing as you suggested.

@gaearon I totally want us to get to this place. The 3.0 rewrite definitely put us in a place where this will be easier to do than before, but we still aren’t quite there. I don’t think you misunderstood something, I think that when I originally proposed this new architecture, I thought that we would have all of the information needed to upgrade enzyme without using any internals… I was wrong.

My goal is to eventually create a new top-level API for enzyme (tentatively called deep) which will use react-test-renderer’s toTree() method. This, along with the mocking abilities it has, I’m hopeful we will be able to reproduce shallow as a subset of the deep API (a bit of an oxymoron going on here).

That leaves mount, which we won’t be able to use react-test-renderer to reproduce, and as a result I think we will continue to need to access internal properties of react unless we can get a toTree() method or something similar that react itself exports. This was the main thing that I didn’t previously understand.

I’m hopeful we will be able to slowly move to less and less of a dependence on internals

@Hedinhiervard using wrapper.update() seem to fix it

I can confirm this behavior with enzyme@3.0.0 and enzyme-adapter-react-16. Upgrading to enzyme@3.0.0, but keeping react@15 works fine.

It works fine for me now with enzyme@3.3.0 and enzyne-adapter-react-15@1.0.5.

It was shouldComponentUpdate for me. There were a couple tests in my codebase that didn’t update with .setProps() even with calling wrapper.update() but those were components that implemented sCU incorrectly—fixing the source code fixed it.

For mount, we might be able to adapt ReactTestUtils to support toTree and the other methods we need for mounting and updating props/state. I proposed something along these lines here https://github.com/facebook/react/issues/9505

That makes sense, thank you for explaining!