Hi Ive been struggling with this and cant seem to get it to work.
Im try to test the value of a select element after a simulate.
it('should select transmission',() =>{
const wrapper = mount(<Transmission/>);
const select = wrapper.find('select').first();
select.simulate('change',{target: {value:"manual"}});
expect(select.props().value).toEqual('manual');
});
const Transmission=(props) =>{
return(
<select name="transmission" onChange={props.handleChange}>
<option value="automatic">Automatic</option>
<option value="manual">Manual</option>
</select>
);
}
export default Transmission;
Even if I remove the onChange method from the select, the error is the same:
Expected value to equal:
"manual"
Received:
undefined
Difference:
Comparing two different types of values. Expected string but received undefined.
Appreciate some help.
simulate does not actually simulate anything; all it does is invoke a prop for you.
I recommend avoiding it entirely, and doing .prop('onChange')() if that's what you want.
Excellent solution, @ljharb. Thank you!
@ljharb I've seen you suggest this in various posts but there are times when just running on change is worthless, because this doesnt actually change the value of the select, so if something depends on the value of the selected option that will not work. this is for UNCONTROLLED selects that do not have a value prop. I have state that is bound to the selects state, I do not change this state in the "onChange" method, this is done automagically by HTML when you select an option in an uncontrolled select, this is what will work in those cases:
await act(async () => {
const option = wrapper.find('.curriculum select option').at(2);
// actually change the selected value of the select
option.simulate('click');
// trigger the change handler, as event propagation is not something enzyme does I believe
wrapper.find('select').simulate('change', {
target: { value: option.prop('value') },
});
});
// update wrapper to reflect these changes
wrapper = await wrapper.update();
@vanor89 i'm not sure what you mean. the onChange indeed does not change the value - the change is what triggers onChange. You, however, can set the value directly, or you can just pass a custom event object into onChange.
You cant set a value of an undefined property. value does not exist in the props of the element, because it is uncontrolled, I only have a defaultValue on it
Right, but in the enzyme tree, you can set the value prop directly on the resulting select, and then invoke onChange. In most cases, you won't need to actually set the value (because you won't be reading it off of the select's ref), so passing it into onChange's event object param would be sufficient.
You cannot set the value prop directly in the resulting select, that throws an error, "value" is undefined.
That is exactly my problem, I am using the selects ref in some testing further on, I have some other selects that populate their options depending on the actual value of the previous selects, if the value of these selects does not change, I cannot expect the other ones to be populated accurately
gotcha. simulate doesn't do that either, though, so either way you have to manually do it.
If you find the select, it's a DOM node - you can .setAttribute('value', 'whatever') directly. Does that not work?
Most helpful comment
simulatedoes not actually simulate anything; all it does is invoke a prop for you.I recommend avoiding it entirely, and doing
.prop('onChange')()if that's what you want.