I have a component MyComponent
with method doSomething
that updates a state, and renderChildren
that renders child components based on these states:
class MyComponent extends Component {
constructor(props) {
super(props);
...
this.state = {
renderChildA: true,
renderChildB: false,
};
}
doSomething = (params) => {
// Do something...
this.setState({
renderChildA: false,
renderChildB: true,
});
}
renderChildren = () => {
const { renderChildA, renderChildB } = this.state;
if (renderChildA) {
return <ChildComponentA />;
} else if (renderChildB) {
return <ChildComponentB />;
}
}
render() {
return (
<div>
{this.renderChildren()}
...
</div>
);
}
}
NOTE: the component is also connected to Redux, but has been simplified.
For unit testing, I'm calling doSomething
and verifying that ChildComponentB
is visible:
test('doSomething should trigger ChildComponentB to pop up', () => {
const wrapper = shallow(
<MyComponent
...
/>,
).dive();
wrapper.instane().doSomething(params); // assume params is defined
const childComponentB = wrapper.find('ChildComponentB');
expect(childComponentB).toHaveLength(1);
});
However, the test case above fails:
my-component.test.jsx > Some test group name > doSomething should trigger ChildComponentB to pop up
expect(received).toHaveLength(length)
Expected value to have length:
1
Received:
// Some giant JSON object
recevied.length:
0
xxx | const childComponentB = wrapper.find('ChildComponentB');
xxx | expect(childComponentB).toHaveLength(1);
xxx | });
Based on the logging, I'm seeing that setState
within doSomething
is triggered after expect
statement in the test case. I suspect this is happening since setState
is asynchronous, but I don't know a workaround for this (other than setTimeout
).