I am trying to test a component. The test worked without styling, but now that I've styled it with Material-UI, the test no longer works. It seems the component, if styled with Material-UI will only render as [object Object] (undefined).
I have a form I'm exporting as: export default withStyles(styles)(ShuttleForm);
But I can test the component ShuttleForm, or any component that uses it now that I'm exporting it withStyles.
How can I test a styled material-ui component? I've looked at the material-ui docs and I've used their createShallow but it hasn't made a difference.
This is my test file:
import React from 'react';
import { createShallow } from '@material-ui/core/test-utils';
import { AddShuttlePage } from '../../components/AddShuttlePage';
import shuttles from '../fixtures/shuttles';
let addShuttle, history, shallow, wrapper;
beforeEach(() => {
addShuttle = jest.fn();
history = { push: jest.fn() };
shallow = createShallow();
wrapper = shallow(<AddShuttlePage addShuttle={addShuttle} history={history} />)
});
test('should render AddShuttlePage correctly', () => {
expect(wrapper).toMatchSnapshot();
});
test('should handle onSubmit', () => {
wrapper.find('ShuttleForm').prop('onSubmit')(shuttles[1]);
expect(history.push).toHaveBeenLastCalledWith('/');
expect(addShuttle).toHaveBeenLastCalledWith(shuttles[1]);
});
It keeps crashing at wrapper.find('ShuttleForm').prop... with a `Method “props” is only meant to be run on a single node. 0 found instead.
My component:
import React from 'react';
import { connect } from 'react-redux';
import ShuttleForm from './ShuttleForm';
import { addShuttle } from '../actions/shuttles';
export class AddShuttlePage extends React.Component {
onSubmit = (shuttle) => {
this.props.addShuttle(shuttle);
this.props.history.push('/');
};
render() {
return (
<div>
<h1>Add Shuttle</h1>
<ShuttleForm
onSubmit={this.onSubmit}
/>
</div>
);
}
}
const mapDispatchToProps = (dispatch) => ({
addShuttle: (shuttle) => dispatch(addShuttle(shuttle))
});
export default connect(undefined, mapDispatchToProps)(AddShuttlePage);
The component that is causing problems:
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import 'react-dates/initialize';
import 'date-fns';
import DateFnsUtils from '@date-io/date-fns';
import { MuiPickersUtilsProvider,
KeyboardTimePicker,
KeyboardDatePicker
} from '@material-ui/pickers';
import { withStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
button: {
margin: theme.spacing(1),
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: 200,
},
});
export class ShuttleForm extends React.Component {
constructor(props) {
super(props);
this.state ={
origin: props.shuttle ? props.shuttle.origin : '',
destination: props.shuttle ? props.shuttle.destination : '',
date: props.shuttle ? moment(props.shuttle.date) : moment(),
time: props.shuttle ? props.shuttle.time : moment(),
spots: props.shuttle ? props.shuttle.spots : '',
cost: props.shuttle ? props.shuttle.cost : '',
error: ''
}
}
onOriginChange = (e) => {
const origin = e.target.value;
this.setState(() => ({ origin }));
};
onDestinationChange = (e) => {
const destination = e.target.value;
this.setState(() => ({ destination }));
};
onDateChange = (date) => {
if (date) {
this.setState(() => ({ date }));
}
};
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarFocused: focused }));
};
onTimeChange = (time) => {
console.log('time',time);
if (time) {
this.setState(() => ({ time }));
}
};
onSpotsChange = (e) => {
const spots = e.target.value;
this.setState(() => ({ spots }));
};
onCostChange = (e) => {
const cost = e.target.value;
this.setState(() => ({ cost }));
};
onSubmit = (e) => {
e.preventDefault();
if (!this.state.origin || !this.state.destination) {
this.setState(() => ({ error: 'Please provide origin and destination.' }));
} else {
this.setState(() => ({ error: '' }));
this.props.onSubmit({
origin: this.state.origin,
destination: this.state.destination,
date: this.state.date.valueOf(),
time: this.state.time.valueOf(),
spots: e.target.elements.spots.value.trim(),
cost: e.target.elements.cost.value.trim(),
});
}
}
render() {
const { classes } = this.props;
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div>
{this.state.error && <p>{this.state.error}</p>}
<form className={classes.root} onSubmit={this.onSubmit}>
<FormControl className={classes.formControl}>
***Form is here but I have removed it for brevity***
<Button variant="contained" className={classes.button} type="submit">Add Shuttle</Button>
</form>
</div>
</MuiPickersUtilsProvider>
);
}
}
ShuttleForm.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(ShuttleForm);