Simulating change on SelectField component using enzyme works but the value of select field is undefined.
//returned element
< div>
< SelectField
value={this.state.selectId}
onChange={this.handleChange}
>
{list.map(
object = > < MenuItem key={object._id} value={object._id} primaryText={object.value} />
)}
handleChange(event, index, value){
console.log(event, index, value)
this.setState({selectId: value})
}
const testTarget = shallow(
it('should select.',
() => {
testTarget.find('SelectField').simulate('change', { target: { value: 'idvalue' } });
}
);
console produces
[event] Object, [index] 0, [value] undefined
However when select component is used normally it works fine.
Got it to work with enzyme simulate 'change' by modifying
Works for testing and normal selects
handleChange( event, index, value){
this.setState({selectId: value||event.target.value})
}
@pricetula can you specify what you modified to get it working, my code is the same as yours and the mocked method is not being called.
@mcohoon the change i made is in my component's handleChange method
handleChange(event, index, value){
console.log(event, index, value)
this.setState({selectId: value})
}
changed to
handleChange( event, index, value){
this.setState({selectId: value||event.target.value})
}
value parameter is undefined when in testing so i normaly have to get it from event.target.value
I dont have the repo right now but i remember running into this issue a couple of times
@pricetula You explain how to handle the right value when the method is called.
Our methods are not being called.
This works for me
import Select from "material-ui/Select"
...
const wrapper = shallow(<MyForm />);
const select = wrapper.find(Select);
expect(select).toHaveLength(1);
select.simulate('change', {target: {value: '1'}});
Alas, this doesn't work for me. 馃槶
// RegionSelect.js
state = {
region: '',
regions: ['West', 'Central', 'East']
}
handleChange = event => {
console.log(event.target.value) // not triggered
this.setState({ region: event.target.value })
}
render() {
const { className } = this.props
const { region, regions } = this.state
return (
<FormControl className={className}>
<InputLabel htmlFor="region">Region</InputLabel>
<Select
value={region}
onChange={this.handleChange.bind(this)}
input={<Input id="region" />}
>
{regions.map((r, i) => (
<MenuItem key={i} value={r}>{r}</MenuItem>
))}
</Select>
</FormControl>
)
}
// RegionSelect.test.js
test('handle submit', () => {
const root = mount(<RegionSelect />)
root.find('Select').simulate('change', { target: { value: 'East' } })
console.log(root.state('region')) // not set
})
@hboylan please try changing your handleChange method in your component to pass in multiple parameters
handleChange = event => {...}
to
handleChange = (event, index, value) => {...} // value || event.target.value
This is because maybe while test it uses event object and value is used when not in test enviroment
@pricetula Thanks for the suggestion!
Unfortunately, the onChange
method isn't triggered at all. I even tried bypassing handleChange
:
onChange={console.log}
(btw I'm on Jest v20.0.4
)
@hboylan I found looking at material-ui's own tests to be helpful. For Select:
wrapper.find('[role="button"]').simulate('click');
wrapper
.find(MenuItem)
.at(3)
.simulate('click');
successfully causes onChange
to fire from a Select for me.
Thanks @city41 !
Although in hindsight this might look quite obvious, I believe this should be added somewhere in the docs for quick lookup.
Edit: My only observation is that although the method mentioned above does trigger the change event, the Menu is not collapsed afterwards as I would expect it to.
This code worked for me:
Component:
import React, { ReactElement, useCallback } from 'react';
import { FormControl, InputLabel, Select, MenuItem, FormHelperText } from '@material-ui/core';
import { useFormikContext, useField } from 'formik';
interface Props {
id: string;
label: string;
name: string;
data: Array<{ value: any; text: string }>;
placeholder?: string;
className?: any;
}
export default function GenericSelectField(props: Props): ReactElement {
const [field, meta] = useField(props);
const { setFieldValue } = useFormikContext();
const handleChange = useCallback(
event => {
setFieldValue(props.name, event.target.value);
},
[props.name, setFieldValue]
);
return (
<FormControl
fullWidth={true}
error={meta.error && meta.touched ? true : false}
className={props.className}
>
<InputLabel htmlFor={props.id}>{props.label}</InputLabel>
<Select
id={props.id}
value={field.value}
onChange={handleChange}
inputProps={{ name: field.name, id: `${props.id}-input` }}
placeholder={props.placeholder}
>
{props.data.map((data, itr) => (
<MenuItem key={itr} value={data.value} id={`menu-item-${itr}`}>
{data.text}
</MenuItem>
))}
</Select>
<FormHelperText id={`${props.id}-helper-text`}>
{meta.error && meta.touched ? meta.error : ''}
</FormHelperText>
</FormControl>
);
}
Test:
import React from 'react';
import { mount } from 'enzyme';
import { Select } from '@material-ui/core';
describe('Select test', () => {
fit('should show form validation errors', async () => {
await act(async () => {
const initialValues = { testSelect: '' };
const validationSchema = Yup.object().shape({
Yup.string().required('This field is required');
});
const wrapper = mount(
<Formik initialValues={initialValues} validationSchema={validationSchema} >
<Form>
<GenericSelectField
id='test-select'
name='testSelect'
label='My Test'
data={[
{ value: 1, text: 'Option 1' },
{ value: 2, text: 'Option 2' },
]}
/>
</Form>
</Formik>
);
expect(wrapper).toBeTruthy();
await wait(0);
wrapper.update();
wrapper.find('form').simulate('submit');
await wait(0);
wrapper.update();
expect(wrapper.find('p[id="test-select-helper-text"]').text()).toBe(
'Esse campo 茅 obrigat贸rio'
);
const changeTarget: any = {
target: { name: 'testSelect', value: 1 },
};
wrapper.find(Select).props().onChange!(changeTarget, null);
await wait(0);
wrapper.update();
expect(wrapper.find('p[id="test-select-helper-text"]').text()).toBe('');
});
});
Most helpful comment
@hboylan I found looking at material-ui's own tests to be helpful. For Select:
https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Select/Select.test.js#L72
successfully causes
onChange
to fire from a Select for me.