Describe the bug
Test fails with strange setState error when multiple childs are rendered and callback is passed to each of them. The strange thing is that setState is called from the production code.
Method “setState” is only meant to be run on a single node. 2 found instead.
79 | return React.Children.map(this.props.children, child => {
80 | return React.cloneElement(child, {
> 81 | onPress: () => this.setState({ name: '::any name::' })
| ^
82 | })
83 | })
84 | }
To Reproduce
class MyComponent extends React.Component {
render() {
return React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
onPress: () => this.setState({ name: '::any name::' })
})
})
}
}
class MyChildComponent extends React.Component {
render() {
return <Text>Hello!</Text>
}
}
// Test
const wrapper = shallow(
<MyComponent>
<MyChildComponent />
<MyChildComponent />
</MyComponent>
)
wrapper
.find(MyChildComponent)
.first()
.props()
.onPress()
expect(wrapper.state()).toEqual({ name: '::any name::' })
Expected behavior
Test to pass
Desktop (please complete the following information):
What's the output of wrapper.find(MyChildComponent).first().props().onPress.toString())
?
What happens if you add a wrapper.update()
before trying to check the state?
What's the output of wrapper.find(MyChildComponent).first().props().onPress.toString())?
function onPress() {return _this.setState({ name: '::any name::' });}
What happens if you add a wrapper.update() before trying to check the state?
Actually the test doesn't fail in the expectation, as it fails when onPress callback is called.
I've tried and with update but the error message is same as code doesn't get to this point at all.
it('bad case', () => {
const wrapper = shallow(
<MyComponent>
<MyChildComponent />
<MyChildComponent />
</MyComponent>
)
console.log(
wrapper
.find(MyChildComponent)
.first()
.props()
.onPress.toString()
)
wrapper
.find(MyChildComponent)
.first()
.props()
.onPress()
wrapper.update()
expect(wrapper.state()).toEqual({ name: '::any name::' })
})
Output:
● (Tabs) Component › bad case
Method “setState” is only meant to be run on a single node. 2 found instead.
79 | return React.Children.map(this.props.children, child => {
80 | return React.cloneElement(child, {
> 81 | onPress: () => this.setState({ name: '::any name::' })
| ^
82 | })
83 | })
84 | }
ahhh this is because enzyme does not yet support components that return non-nodes - ie, an array. If you wrap the React.Children.map
in a React.Fragment
everything will work.
See #1149; closing this one in favor of that.
Most helpful comment
ahhh this is because enzyme does not yet support components that return non-nodes - ie, an array. If you wrap the
React.Children.map
in aReact.Fragment
everything will work.See #1149; closing this one in favor of that.