Reputation: 537
I'm new to React testing and I'm having a hard time figuring out the following issue:
I'm trying to simulate an input onChange event. It's a text input that filters the results in a table. InteractiveTable
has a controlled input field (ControlledInput
) and an instance of Facebook's FixedDataTable
.
This is the test:
let filter = ReactTestUtils.findRenderedComponentWithType(component, ControlledInput);
let input = ReactTestUtils.findRenderedDOMComponentWithTag(filter, 'input');
input.value = 'a';
ReactTestUtils.Simulate.change(input);
console.log(component.state);
On input change the component updates its state with the value of the input, but since setState
is asynchronous, here the console.log will log out the previous state, and I can't query the structure of the component for testing, because it's not updated yet. What am I missing?
Edit: to be clear, if I make the assertion in a setTimeout, it will pass, so it's definitely a problem with the asynchronous nature of setState.
I found one solution, where I overwrite the componentDidUpdate
method of the component:
component.componentDidUpdate = () => {
console.log(component.state); // shows the updated state
let cells = ReactTestUtils.scryRenderedComponentsWithType(component, Cell);
expect(cells.length).toBe(30);
done();
};
This wouldn't be possible if the component had its own componentDidUpdate method, so it's not a good solution. This seems to be a very common problem, yet I find no solution to it.
Upvotes: 2
Views: 1148
Reputation: 379
Normally when I run into similar scenarios when testing, I try to break things apart a little. In your current test, (depending on your flavor of test framework), you could mock the component's setState
method, and simply ensure that it's called with what you expect when you simulate a change.
If you want further coverage, in a different test you could call the real setState
with some mock data, and then use the callback to make assertions about what's rendered, or ensure other internal methods are called.
OR: If your testing framework allows for simulating async stuff, you could try calling that too and test the whole thing in one go.
Upvotes: 2