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?
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 馃嵑
Most helpful comment
Looking at this, it seems like you are mis-rendering your tree in the
mountcall for your test case. Testing on children is fully possible already.Since
AppLayoutrenders it's children, you have to pass it children. I think you just need to do this change:Calling
.html()on thewrappercan help you see the tree enzyme has access to.