Enzyme - How to access and set <input> value?
Unit TestingReactjsEnzymeUnit Testing Problem Overview
I'm confused about how to access <input>
value when using mount
. Here's what I've got as my test:
it('cancels changes when user presses esc', done => {
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.render().attr('value'));
input.simulate('focus');
done();
});
The console prints out undefined
. But if I slightly modify the code, it works:
it('cancels changes when user presses esc', done => {
const wrapper = render(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.val());
input.simulate('focus');
done();
});
Except, of course, the input.simulate
line fails since I'm using render
now. I need both to work properly. How do I fix this?
EDIT:
I should mention, <EditableText />
is not a controlled component. But when I pass defaultValue
into <input />
, it seems to set the value. The second code block above does print out the value, and likewise if I inspect the input element in Chrome and type $0.value
in the console, it shows the expected value.
Unit Testing Solutions
Solution 1 - Unit Testing
I think what you want is:
input.simulate('change', { target: { value: 'Hello' } })
You shouldn't need to use render()
anywhere to set the value. And just FYI, you are using two different render()
's. The one in your first code block is from Enzyme, and is a method on the wraper object mount
and find
give you. The second one, though it's not 100% clear, is probably the one from react-dom
. If you're using Enzyme, just use shallow
or mount
as appropriate and there's no need for render
from react-dom
.
Solution 2 - Unit Testing
With Enzyme 3, if you need to change an input value but don't need to fire the onChange
function you can just do this (node
property has been removed):
You can use wrapper.find('input').simulate("change", { target: { value: "foo" }})
to invoke onChange
if you have a prop for that (ie, for controlled components).
Solution 3 - Unit Testing
Got it. (updated/improved version)
it('cancels changes when user presses esc', done => {
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
input.simulate('focus');
input.simulate('change', { target: { value: 'Changed' } });
input.simulate('keyDown', {
which: 27,
target: {
blur() {
// Needed since <EditableText /> calls target.blur()
input.simulate('blur');
},
},
});
expect(input.get(0).value).to.equal('Hello');
done();
});
Solution 4 - Unit Testing
So lots of different opinions here. The only thing that worked for me was none of the above, it was using input.props().value
. I hope that helps.
Solution 5 - Unit Testing
I'm using react with TypeScript and the following worked for me
wrapper.find('input').getDOMNode<HTMLInputElement>().value = 'Hello';
wrapper.find('input').simulate('change');
Setting the value directly
wrapper.find('input').instance().value = 'Hello'`
was causing me a compile warning.
Solution 6 - Unit Testing
I am using create-react-app which comes with jest by default and enzyme 2.7.0.
This worked for me:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input')[index]; // where index is the position of the input field of interest
input.node.value = 'Change';
input.simulate('change', input);
done();
Solution 7 - Unit Testing
None of the above worked for me. This is what worked for me on Enzyme ^3.1.1:
input.instance().props.onChange(({ target: { value: '19:00' } }));
Here is the rest of the code for context:
const fakeHandleChangeValues = jest.fn();
const fakeErrors = {
errors: [{
timePeriod: opHoursData[0].timePeriod,
values: [{
errorIndex: 2,
errorTime: '19:00',
}],
}],
state: true,
};
const wrapper = mount(<AccessibleUI
handleChangeValues={fakeHandleChangeValues}
opHoursData={opHoursData}
translations={translationsForRendering}
/>);
const input = wrapper.find('#input-2').at(0);
input.instance().props.onChange(({ target: { value: '19:00' } }));
expect(wrapper.state().error).toEqual(fakeErrors);
Solution 8 - Unit Testing
This works for me using enzyme 2.4.1:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.node.value);
Solution 9 - Unit Testing
In case anyone is struggling, I found the following working for me
const wrapper = mount(<NewTask {...props} />); // component under test
const textField = wrapper.find(TextField);
textField.props().onChange({ target: { value: 'New Task 2' } })
textField.simulate('change');
// wrapper.update() didn't work for me, need to find element again
console.log(wrapper.find(TextField).props()); // New Task 2
It seems that you need to define what happens in the change event first and then simulate it (instead of simulating the change event with data)
Solution 10 - Unit Testing
None of the solutions above worked for me because I was using Formik and I needed to mark the field "touched" along with changing the field value. Following code worked for me.
const emailField = orderPageWrapper.find('input[name="email"]')
emailField.simulate('focus')
emailField.simulate('change', { target: { value: '[email protected]', name: 'email' } })
emailField.simulate('blur')
Solution 11 - Unit Testing
In my case i was using ref callbacks,
<input id="usuario" className="form-control" placeholder="Usuario"
name="usuario" type="usuario"
onKeyUp={this._validateMail.bind(this)}
onChange={()=> this._validateMail()}
ref={(val) =>{ this._username = val}}
>
To obtain the value. So enzyme will not change the value of this._username.
So i had to:
login.node._username.value = "[email protected]";
user.simulate('change');
expect(login.state('mailValid')).toBe(true);
To be able to set the value then call change . And then assert.
Solution 12 - Unit Testing
here is my code..
const input = MobileNumberComponent.find('input')
// when
input.props().onChange({target: {
id: 'mobile-no',
value: '1234567900'
}});
MobileNumberComponent.update()
const Footer = (loginComponent.find('Footer'))
expect(Footer.find('Buttons').props().disabled).equals(false)
I have update my DOM with componentname.update()
And then checking submit button validation(disable/enable) with length 10 digit.
Solution 13 - Unit Testing
I solved in a very simple way:
- Set the value from props:
const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
- Html code:
<input type='text' defaultValue={props.name} className='edituser-name' />
- Access the attribute from
wrapper.find(element).props().attribute-name
:
it('should render user name', () => {
expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
});
Cheers
Solution 14 - Unit Testing
This worked for me:
let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");
Solution 15 - Unit Testing
I use Wrapper's setValue[https://vue-test-utils.vuejs.org/api/wrapper/#setvalue-value] method to set value.
inputA = wrapper.findAll('input').at(0)
inputA.setValue('123456')
Solution 16 - Unit Testing
.simulate()
doesn't work for me somehow, I got it working with just accessing the node.value
without needing to call .simulate()
; in your case:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input').at(0);
// Get the value
console.log(input.node.value); // Hello
// Set the value
input.node.value = 'new value';
// Get the value
console.log(input.node.value); // new value
Hope this helps for others!