Enzyme: Unable to Mount and Traverse {this.props.children}

Created on 8 May 2016  路  4Comments  路  Source: enzymejs/enzyme

When mounting a component that contains {this.props.children}, i.e. a layout component that renders a child page component inside of it, Enzyme is unable to find the child. Example:

Layout:

class AppLayout extends Component {
  render() {
    return (
        <div>

          ...

          <div className="page-container">
            {this.props.children}
          </div>

          ...

        </div>
    );
  }
}

Page (child):

class ChildPage extends Component {
  render() {
    return (
        <div>

          ...

          <TopBar />

          ...

        </div>
    );
  }
}

Enzyme:

    it('can find a child page', function () {
      const wrapper = mount(<AppLayout />);
      wrapper.find('TopBar').simulate('click'); // fails here
      expect( ... ).toEqual( ... );
    });

Failure error:

Error: This method is only meant to be run on single node. 0 found instead.
    at ReactWrapper.single (packages/modules.js?hash=0fff7a1c686c8053d1feaf04955a09c8985d8b5f:25973:17)
    at ReactWrapper.simulate (packages/modules.js?hash=0fff7a1c686c8053d1feaf04955a09c8985d8b5f:25405:14)
    at Context.<anonymous> (app/app.js?hash=f0f11fe007a6493261baeb562e64e4dbd0fff573:848:36)
    at callFn (packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3227:21)
    at Test.Runnable.run (packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3220:7)
    at Runner.runTest (packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3688:10)
    at packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3799:12
    at next (packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3608:14)
    at packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3618:7
    at next (packages/practicalmeteor_mocha.js?hash=489e07e2e98906b5ed07059bc93d8f53fe79c00b:3550:14)

What is the preferred way to handle this situation? While the example given above is rather lame, this is a very useful feature to have for cases where you'd like to perform events on children to evaluate state changes on the root / parent.

Thanks!

EDIT: Maybe the better question to ask here is, how to define the "context" of the parent such that it can find the child to render? Perhaps explicitly telling it which child to render?

invalid

Most helpful comment

Looking at this, it seems like you are mis-rendering your tree in the mount call for your test case. Testing on children is fully possible already.

Since AppLayout renders it's children, you have to pass it children. I think you just need to do this change:

-const wrapper = mount(<AppLayout />);
+const wrapper = mount(<AppLayout><ChildPage /></AppLayout);

Calling .html() on the wrapper can help you see the tree enzyme has access to.

All 4 comments

Looking at this, it seems like you are mis-rendering your tree in the mount call for your test case. Testing on children is fully possible already.

Since AppLayout renders it's children, you have to pass it children. I think you just need to do this change:

-const wrapper = mount(<AppLayout />);
+const wrapper = mount(<AppLayout><ChildPage /></AppLayout);

Calling .html() on the wrapper can help you see the tree enzyme has access to.

Thanks for your reply. When I try the following:

      const wrapper = mount(
        <AppLayout>
          < ChildPage />
        </AppLayout>
      );

I get the following error:

TypeError: Cannot read property 'pathname' of undefined
    at AppLayout.render (app/app.js?hash=3770df093b4e3a14f12a2a31ffe2e4513bb9e381:914:22)
    at ReactCompositeComponentMixin._renderValidatedComponentWithoutOwnerOrContext (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:16461:34)
    at ReactCompositeComponentMixin._renderValidatedComponent (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:16481:32)
    at wrapper [as _renderValidatedComponent] (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:9542:21)
    at ReactCompositeComponentMixin.performInitialMount (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:16065:30)
    at ReactCompositeComponentMixin.mountComponent (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:15996:21)
    at wrapper [as mountComponent] (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:9542:21)
    at Object.ReactReconciler.mountComponent (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:9621:35)
    at ReactCompositeComponentMixin.performInitialMount (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:16071:34)
    at ReactCompositeComponentMixin.mountComponent (packages/modules.js?hash=0da348cabffcfe8a4fe4b6c788b47170e2655c18:15996:21)

Any ideas? I'm using React Router. ChildPage (/child) is a child of AppLayout (/).

Does your component expect a pathname value from props? You may need to mock the data.

@Aweary Thank you! Turns out this wasn't an "issue", but rather an effort to marry Enzyme with React Router to achieve the test I'm looking for. React Router creates some props on AppLayout that I needed to pass in to set the context of the test:

      const wrapper = mount(
        <AppLayout location={{ pathname: '/' }}>
          <ActivityPage />
        </AppLayout>,
        'en-US'
      );

Cheers 馃嵑

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nelsonchen90 picture nelsonchen90  路  3Comments

heikkimu picture heikkimu  路  3Comments

benadamstyles picture benadamstyles  路  3Comments

potapovDim picture potapovDim  路  3Comments

andrewhl picture andrewhl  路  3Comments