enzyme: simulate behavior is not as expected

Please suggest how to fix this scenario to simulate currentTarget object :

let TestComponent = React.createClass({
 updateField(event){
    console.log(event.target.value);
    console.log(event.currentTarget.value);

    this.setState({
      value: event.currentTarget.value
    });
  },

  render(){
    return <input value={this.props.value} onChange={this.updateField} />
  }
});

target.value is available in the event object as expected

let component = mount(<TestComponent />);
let input = component.find("input");
input.simulate("change", {target:{value:"hello"});

currentTarget.value is NOT available in the event object as expected, currentTarget is a real dom object. Looks like jsdom is overwriting it?

let component = mount(<TestComponent />);
let input = component.find("input");
input.simulate("change", {currentTarget:{value:"world"});

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 23
  • Comments: 18 (6 by maintainers)

Most upvoted comments

I solved this by doing:

input.getDOMNode().value = "another_new_value";
input.simulate("change");

Two years later and still no update?

I too am finding this issue. I was using event.target.value in my <input /> change handler before, but after getting some Typescript type errors for using it and reading this post about how event.currentTarget instead of event.target is the actual correct value to use, I found my enzyme tests broke.

Now, when I try setting event.currentTarget in my simulated change event, it currentTarget doesn’t get set. Like so:

const enzymeWrapper = mount(<MyComponent />);
const input = enzymeWrapper.find('.myInput');
input.simulate("change", { target: { value: "new_value" } }); // event.target is properly set in the change handler
input.simulate("change", { currentTarget: { value: "another_new_value" } }); // event.currentTarget is not set in the change handler 

Don’t think this is how this is supposed to behave. It does seem to work if I use shallow() though.

It’s been over a year, any updates on this? I’m having the same problem.

// MyInput.js

<input onChange={(event) => {
  console.log(event.currentTarget.value)} // undefined
  console.log(event.target.value)} // 'foo'
}/>

In my test:

const eventObject = value => ({ currentTarget: { value }, target: { value } });
const wrapper = mount(<MyInput />);
wrapper.find('input').simulate('change', eventObject('foo'));

My current solution is to use:

wrapper.find('input').props().onChange(eventObject('foo')));

Through my limited research, this seems to be an issue related to mount and jsdom.

(Sorry for reviving an old thread, but this is what came up in a Google search, and I see this issue is still open.)

Edit: Relevant conversation here as well: https://github.com/airbnb/enzyme/issues/76

A PR with a failing test case would be helpful.

In general though, I suggest never using simulate, as it does not faithfully simulate anything. If you want to invoke a prop callback like onClick, invoke it directly with .prop('onClick')().

This seemed to work for me:

const wrapper = mount(/*Omitted*/).find('form');
wrapper.simulate('submit', { currentTarget: wrapper.getDOMNode() });

I think this should be natively supported though.

@ljharb isn’t getting into props an implementation detail though? I don’t particularly want to know a lot about the component/React API, I just want to know something fired correctly when I update a value in an input element.

The underlying culprit has been closed! https://github.com/facebook/react/issues/4950. Methinks the Enzyme folks should weigh-in. currentTarget is a no-brainer MUST HAVE for simulate() to be useful.

You can properly simulate this in shallow renders because it does not have a DOM. But mounted renders actually use the dom, which then the event system kicks out the real event with real nodes.

I’m not sure if there would be a way to over-ride the values in enzyme or not. If you could take a look into it and submit a working PR that would be great.

Otherwise, I am seeing for myself that if I do this test, the currentTarget.value === input.value

e.g.,

wrapper = mount(<input value="foo" onChange={e => console.log(e.currentTarget.value)} />);
wrapper.simulate('change');
// logs `"foo"`