Enzyme: Please some information about find() as a snapshot to docs

Created on 7 Apr 2020  路  11Comments  路  Source: enzymejs/enzyme

Current behavior

Hello, I would simply like to request that the documentation for find() (https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/find.html) be updated to reflect its snapshot-nature. For example, in a situation where clicking a button updates state under the hood...

   // some set up code goes here. 

    const deleteButton = wrapper.find('[data-enzyme-id="someid"]').first();
    deleteButton.simulate('click');

    expect(wrapper.find("#modal").first().props().isOpen).toBe(true)

the above code will work, but the below will not:

    const modals = wrapper.find("#modal");
    const deleteButton = wrapper.find('[data-enzyme-id="someid"]').first();
    deleteButton.simulate('click');

    expect(modals.first().props().isOpen).toBe(true)

Presumably, this is because the objects that are returned by find() do not reflect the actual DOM tree, but a snapshot thereof.

It would be great to see this mentioned briefly in the documentation. Please suggest a way to explain this in a documentation-appropriate manner. Thank you!

docs help wanted

All 11 comments

This applies not just to find, but to every enzyme API - you always have to re-traverse from the root.

It's described here: https://github.com/enzymejs/enzyme/blob/master/docs/guides/migration-from-2-to-3.md#element-referential-identity-is-no-longer-preserved but it might be useful to summarize and link to it on all the relevant methods' docs.

Thank you for the reference!

I found the example for Calling props() after a state change in this doc is incorrect. The first test statement should fail in v3, but it passed. I wonder would that be caused by the mount() method is full DOM rendering.

I want to work on this issue and summarize it and link it to all relevant methods.

@cadence09 thanks, that would be great!

It's entirely possible the migration guide, written for v3.0.0, has become incorrect over time; it's important we identify what may have inadvertently broken vs what was a bug that's been fixed :-)

@ljharb I summarized the v3 migration guide to this "In Enzyme v3, it transforms React's render tree into an intermediate representation, so it no longer has direct access on the representation of the render tree that React itself has and it needs to retraverse and inspect when there is a state change. However, mount() is full DOM rendering, traverse is not necessary. More information on migration guide for enzyme v3.x" and I put it to all relevant ReactWrapper methods with traversing tests. Would this be good ? I will work on the ShallowWrapper API.

@cadence09 i'm not 100% sure what you're proposing, but a) refining the existing text to be more accurate is always good, b) adding new sections that are relevant to migrating from v2 to v3 is good.

Over the years it's become apparent that there's a few important things in the migration guide that are useful for people who aren't migrating at all - ie, just normal v3 users - and it's likely a really good idea to find a place in the general documentation for this stuff, including the "always re-find from the root after changes have been made" category of issues. I'd be more than happy to review PRs that add that sort of thing as well.

@cadence09 thanks, that would be great!

It's entirely possible the migration guide, written for v3.0.0, has become incorrect over time; it's important we identify what may have inadvertently broken vs what was a bug that's been fixed :-)

I found the example for Calling props() after a state change in this doc is incorrect. The first test statement should fail in v3, but it passed. I wonder would that be caused by the mount() method is full DOM rendering.

@ljharb Sorry for the confusion. When I have been working on the ReactWrapper API to check what may have broken, I noticed the using mount() for testing is not necessary to re-find from the root and using shallow() will need to re-find from the root when a state has been changed, so I refined the text. And yes, I can add a new section for it. Should I create a new file in the Enzyme's guides folder for this new section and your review?

I also noticed there are couple tests is failing in ReactWrapper API. Should I create a commit for each ReactWrapper method that I have been changed?

Hmm, that's surprising - mount and shallow should be behaving the same in this respect.

Yes, if there's failing tests I'd love fixes; separate commits is always appreciated.

I thought the same way too. I post the code and tests below for your review. The Toggler class example comes from the migration. All first three tests passed on my side expect the last test. The first test using mount() without re-finding from the root passed the test, and the last test using shallow() without traversing from the root failed. I think it is because mount() is full Dom rendering, so traversing from the root is not necessary. The last test failed I initially thought it is because shallow() returns the output of the render method, so the traverse is necessary. However, when I continued to reproducenmore test examples from ReactWrapper API, I noticed the shallow() without traverse from the root also passed on the examples with a static value. On the last test from Toggler class, when I updated the 'on' value with false in toggle() and made expect() result equals off to test my assumption, the return output stayed false and the test passed. So I think traversing from the root is necessary when the state is changed.

class Toggler extends React.Component {
    constructor(...args) {
      super(...args);
      this.state = { on: false };
    }

    toggle() {
      this.setState(({ on }) => ({ on: !on }));
    }

    render() {
      const { on } = this.state;
      return (<div id="root">{on ? 'on' : 'off'}</div>);
    }
}
// testing for mount()
  it('passes in enzyme v2, fails in v3', () => {
    const wrapper = mount(<Toggler />);
    const root = wrapper.find('#root');
    expect(root.text()).toEqual('off');

    wrapper.instance().toggle();

    expect(root.text()).toEqual('on');
  });

  it('passes in v2 and v3', () => {
    const wrapper = mount(<Toggler />);
    expect(wrapper.find('#root').text()).toEqual('off');

    wrapper.instance().toggle();

    expect(wrapper.find('#root').text()).toEqual('on');


  });

  //testing for shallow()
  it('need re-find from the root',()=>{
    const wrapper = shallow(<Toggler />);
    expect(wrapper.find('#root').text()).toEqual('off');

    wrapper.instance().toggle();

    expect(wrapper.find('#root').text()).toEqual('on');
  })

  it('not passing without re-finding from the root',()=>{
    const wrapper = shallow(<Toggler />);
    const node=wrapper.find('#root')
    expect(node.text()).toEqual('off');

    wrapper.instance().toggle();

    expect(node.find('#root').text()).toEqual('on');
  })

Per our offline discussion, let's start with a PR that contains currently-passing tests, and after that, we can explore what changes would be desired to try to make mount and shallow consistent.

Was this page helpful?
0 / 5 - 0 ratings