currentTarget not working when using mount
const wrapper = mount(<input type="text" onChange={(e)=> console.log(e.currentTarget.value)}/>)
wrapper.simulate('change', {currentTarget: {
value: 'Hello'
}});
currentTarget working when using shallow
const wrapper = shallow(<input type="text" onChange={(e)=> console.log(e.currentTarget.value)}/>)
wrapper.simulate('change', {currentTarget: {
value: 'Hello'
}});
const wrapper = mount(<input type="text" onChange={(e)=> console.log(e.currentTarget.value)}/>)
wrapper.simulate('change', {currentTarget: {
value: 'Hello'
}});
| library | version
| ------------------- | -------
| enzyme | 3.1.15
| react | 16.6.3
| react-dom | 16.6.3
| react-test-renderer | 16.6.3
| adapter (below) | 1.0.3
I would suggest avoiding .simulate - it doesn't faithfully simulate anything. Instead, manually invoke the desired prop - ie, wrapper.prop('onChange')(fakeEvent).
@ljharb's solution worked for me but the documentation (mount > simulate) says that any object you pass to the simulate method as a second parameter, will be passed to the event handler. But the truth is that it's not currently working when using mount but it does work with shallow.
Maybe we should update the documentation to warn about this? If not, isn't it a bug?
On the other hand, it seems that @ljharb has been advising people to use wrapper.prop('eventName') instead of .simulate for a long time. What is the use of simulate then?
Thank you
simulate only exists in enzyme because it was present in react-test-renderer, and we added it to enzyme before realizing that it's badly named and unreliably implemented.
I do agree that if the documentation is wrong, and/or if mount/shallow are inconsistent without good reason, then that's something that should be fixed. @Totemika can you file a new issue about that part, with repro code (showing the difference between shallow and mount)?
Why does simulate behave differently in mount and shallow? I am writing an integration test and I'd rather not trigger an event in an artificial way like by triggering an onChange prop, as I want to keep the test as similar to the browser as possible.
@steveHornseyDeveloper triggering the onChange prop is the proper way to do it; if you're not using something like webdriver to make an actual click, then you're not getting any value out of implicitly calling onChange by using simulate.
@steveHornseyDeveloper triggering the onChange prop is the proper way to do it; if you're not using something like webdriver to make an _actual_ click, then you're not getting any value out of implicitly calling
onChangeby using simulate.
Perhaps if triggering the desired handler from the mounted component's props is the "proper" way to do it, then this fact should be documented somewhere?
Searching Google for "enzyme trigger event" gives results where every link on the first page tells you to use .simulate(), the first two of which are links to the official Enzyme docs.
Further, all the examples of triggering events in Enzyme's official docs suggest to use .simulate().
Even just mentioning what you've said in this issue thread under the common gotchas of this function would be a lot clearer than users having to dig through threads to find this information.
A PR to improve the docs in the way you suggest would be appreciated.
Apologies if my last comment came off as abrasive, I was trying to express bewilderment that the correct way to do something as essential as testing event behaviour isn't really documented
I'd be happy to submit a PR, but what I'm thinking though is if this is really the recommended way to trigger events on components you're testing in Enzyme, there should probably be a dedicated guide on testing events using this method or at least a section on the .prop() or .invoke() page showing it used for that rather than just a footnote on the .simulate() page, because there's a lot of misinformation on the web instructing people to use .simulate() and when reading the docs it looks like that's the de-facto method to test event handlers on your components, so a more extensive and visible correction to that might help a lot more.
If that would be a welcome change I'm happy to have crack at writing it, otherwise I'll just write an added gotcha on the .simulate() page.
@kunyan yes, this tripped me up too. I had to use event.target to get it working with mount.
However I found if you try and use event.target with shallow, then it fails.
So you need event.currentTarget to work with shallow
and event.target to work with mount
fyi wrapper.prop('onChange')(fakeEvent) does seem to work but you get lots of angry red text
console.error node_modules/react-dom/cjs/react-dom.development.js:558
Warning: An update to ComponentWithNxTextInput inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act
in ComponentWithNxTextInput (created by WrapperComponent)
in WrapperComponent
What is the right way to do this?! This seems like a fairly basic thing to be broken out of the box.
I found an approach that seems to work in this thread: https://github.com/enzymejs/enzyme/issues/218
const mountedComponent = mount(<ComponentWithNxTextInput />);
const input = mountedComponent.find('input');
input.getDOMNode().setAttribute('value', givenInputValue);
input.simulate('change', { currentTarget: input });
The key is pointing currentTarget to a real dom node reference. This seems to work better than props('onChange') avoiding all that ugly red text I mentioned.
Most helpful comment
I would suggest avoiding
.simulate- it doesn't faithfully simulate anything. Instead, manually invoke the desired prop - ie,wrapper.prop('onChange')(fakeEvent).