So I started with unit testing React components composed of Material-UI components using Jest and Enzyme setup. So far every event simulation was working fine until I encountered Select component from Material-UI. (More info below)
Project was bootstrapped using create-react-app and utilized material-ui-next.
Dependencies Version
- React: 16.2.0
- React-Dom: 16.2.0
- React-Scripts: 1.1.1
- Material UI: 1.0.0-beta.35
- Jest: One that comes packed with setup (22.4.3)
- Enzyme: 3.3.0
- Enzyme Adapter React 16: 1.1.1
Problem
I have a pure functional component named FiltersDesktop composed of Material-UI form fields. Three of which are Select components and others are textfield and date picker from material-ui.
UI Code
<Collapse in={props.visible} className={'filters-container-desk'}>
<Grid container classes={{ typeContainer: "filter-container" }} id={'container-desk'}>
<Grid item lg={2} xl={2}>
<FormControl fullWidth={true}>
<InputLabel htmlFor="sources">Sources</InputLabel>
<Select
open
inputProps={{ name: 'sources-desk', id: 'sources-desk' }}
value={props.filters.source || ''}
onChange={(event) => props.updateFilter({ source: event.target.value })}
>
<MenuItem value=''>
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item lg={2} xl={2}>
...
</Grid>
... // More Grid components of similar structure as above
</Grid>
</Collapse>
When I try to simulate change event on textfield component it works fine. Following is the code I wrote for testing a textfield:
Test Code for TextField
const props = {
updateFilter: jest.fn()
};
test(`updateFilter should get called on simulating text changes in domain`, () => {
const component = mount(<FiltersDesktop {...this.props} />);
component.find('#domain-desk').last().simulate('change', { target: { value: 'scoopwhoop.com' } });
expect(props.updateFilter).toHaveBeenCalled();
});
But something similar doesn't work for Select component. However the update function gets called when I actually interact with the Select field via interface. Following is the test code I wrote for testing Select:
Test Code for Select
const props = {
updateFilter: jest.fn()
};
test(`updateFilter should get called on simulating text changes in sources`, () => {
const component = mount(<FiltersDesktop {...this.props} />);
// Did not work
component.find('#sources-desk').last().simulate('change', { target: { value: 20 } });
// Did not work
component.find('Select').first().simulate('change', { taget: { value: 20 } });
// Did not work
component.find('#sources-desk').forEach(element => element.simulate('change', { taget: { value: 20 } }))
expect(props.updateFilter).toHaveBeenCalled();
});
For some reasons find method always returned me more than 1 elements in all above cases hence I resorted to use first, last and forEach in appropriate cases.
Kindly help my figure out the reason behind the change event not being triggered on Select component on simulating it.
Rest be assured that I have spent atleast a week reading issues on Github, trying to implement the solutions and test guides for Jest and Enzyme. I am sure my test setup is fine as rest of the cases are working fine.
If you want to look at the source code precisely then here is the link to the repository. Pull requests on repository are also appreciated. If you are on repository, then don't forget to switch to react-material branch.
P.S - Don't laugh as I just have recently started with React :P