I'm trying to test how a component renders based on various state and prop changes, as it renders differently depending on props and state. I have something like this:
// Greeting.js
class Greeting extends Component {
state = {
name: '',
};
handleNameChange = (name) => {
this.setState({ name });
}
render() {
const { initialName } = this.props;
const { name } = this.state;
const needName = !(name || initialName);
return (
<div>
{needName &&
<TextField onChange={this.handleNameChange} />
}
</div>
);
}
}
// Greeting.spec.js
const initialProps = {
initialName: null,
};
const component = mount(<Greeting {...initialProps} />)
describe('<Greeting />', () => {
it('shows the textfield if we do not have a name for the user', () => {
// this passes as expected
expect(component.find('TextField').length).toEqual(1);
});
it('does not show the textfield if we have a name for the user', () => {
component.setProps({
initialName: 'Bob',
}, () => {
// this fails with an "expected 1 to equal 0"
expect(component.find('TextField').length).toEqual(0);
})
});
});
Behavior is similar when using .setState(). I've also tried forcing a rerender by calling .update(), but that has not fixed the issue. I may be misunderstanding how .setProps() and .setState() work, but the documentation mentions that the component rerenders, which would seem to suggest that it calls the render function again with the new props/state.
(I'd recommend doing the mount call inside an it or beforeEach, so that if it fails, it fails your tests instead of killing the process)
Typically what's done is that you newly create the element in each test rather than reusing it and using setProps - that said, I would expect it to rerender (with .update() for sure). What does Greeting look like?
That's a good idea - the reason I'm not is because re-mounting on each it makes the tests run a little slower.
Greeting pretty much looks like the example component here, with a few lifecycle methods and some other components around the name entry field. Everything is working in the browser, enzyme is able to find the other components (for example the header above the textfield), and the conditional render logic is working whether I pass an initialName or not - the only thing that's causing a problem is rerendering on the updated props/state 馃
Also potentially relevant: If I put a console.log statement in render, it is only getting logged once (when the component mounts).
In this simple of a component, you may want to shallow-render it (while that's still not solving the original problem, it would help to figure out if the rerendering is working on shallow)
Shallow seems to work as expected
I forgot I'm wrapping Greeting in a redux provider. That's the issue. D'oh.
Most helpful comment
I forgot I'm wrapping
Greetingin a redux provider. That's the issue. D'oh.