Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulate.mouseEnter and Simulate.mouseLeave not working #1297

Closed
leoasis opened this issue Mar 24, 2014 · 17 comments · Fixed by #1366
Closed

Simulate.mouseEnter and Simulate.mouseLeave not working #1297

leoasis opened this issue Mar 24, 2014 · 17 comments · Fixed by #1366

Comments

@leoasis
Copy link

leoasis commented Mar 24, 2014

While testing I wanted to simulate mouseEnter and mouseLeave events, but for some reason they are not firing the handlers in the component.

Here's a fiddle to show you: http://jsfiddle.net/leoasis/RH2vm/
You'll see that with the Simulate functions, only the click is actually triggered, while the other ones not. With the real events everything works perfectly.

I tried to debug a little bit what's going on, but didn't get much information, especially since it's the first time I'm diving into the events mechanism internals in React.

If you want more info, then I can try and dig a bit deeper, but I think the fiddle is clear enough.

@sophiebits
Copy link
Collaborator

Yeah, unfortunately mouseEnter/mouseLeave don't get simulated properly at the moment due to their unique bubbling situation. The biggest blocker here is picking a good API, I think.

Maybe just Simulate.mouseEnterLeave(from, to)?

@leoasis
Copy link
Author

leoasis commented Apr 5, 2014

Why should the user care about where the mouse moves from/to? Perhaps this can be handled internally? Is the problem due to bubbling here? I may need to dive into the code a little more to get a better understanding and stop saying nonsense :P

@sophiebits
Copy link
Collaborator

Yes, it's due to bubbling. If you have the DOM structure

<A>
  <B><C /></B>
  <D />
</A>

and your mouse moves from C to D, then C and B receive mouseleave events, D receives a mouseenter event, and A receives nothing. All other events bubble up to the root.

Perhaps it's good enough to just make simulated mouseEnter and mouseLeave events not bubble at all.

@leoasis
Copy link
Author

leoasis commented Apr 6, 2014

That would work at least where I was trying to test. While testing I generally don't need anything too complex, just making sure the right behavior triggers when the event happens. Hopefully that's the way others do as well

@sophiebits
Copy link
Collaborator

(As a workaround for now, you can use SimulateNative.mouseOver and SimulateNative.mouseOut (making sure to specify relatedTarget appropriately on each) and together they will cause React to fire onMouseEnter and onMouseLeave events.)

@tiye
Copy link

tiye commented Oct 16, 2014

Do we have a good solution for such case now? I'm trying my solution but feeling so tricky.

    componentDidMount: ->
      root = @refs.root.getDOMNode()
      root.onmouseenter = @onMouseEnter
      root.onmouseleave = @onMouseLeave

    onMouseEnter: (event) ->
      console.log 'enter\t', event.target.className
    onMouseLeave: (event) ->
      console.log 'leave\t', event.target.className

And I got still quite strange results:

enter    side-rooms-view
enter    
leave    side-rooms-view
enter    side-rooms-view
enter    side-rooms-header list-title
leave    side-rooms-view

@ryanzec
Copy link

ryanzec commented Dec 21, 2014

@spicyj can you give an example. I can't find any documentation on SimulateNative or how to set relatedTarget appropriately?

@blakehaswell
Copy link

@ryanzec You want to do something like this:

function simulateMouseOver(from, to) {
    simulateNative.mouseOut(from, { relatedTarget: to });
    simulateNative.mouseOver(to, { relatedTarget: from });
}

The simulates the mouse moving from one element to another. The from element can be anything really, it’s not important.

@warmhug
Copy link

warmhug commented Jan 13, 2015

Do we have a good solution for such case now? or It can not be solved?

@ryanzec
Copy link

ryanzec commented Jan 13, 2015

I am manually applying this patch until it is pulled into the core:

#1366

sophiebits added a commit to sophiebits/react that referenced this issue Feb 17, 2015
Fixes facebook#1297.

onMouseEnter and onMouseLeave shouldn't *actually* use direct dispatch, but doing so is more useful than doing nothing (and I don't think it precludes adding proper enter/leave dispatching later, either).

Test Plan:
grunt test
@ryanzec
Copy link

ryanzec commented Apr 11, 2015

Any update on this?

@brianblocker
Copy link

I was able to get my tests to pass using SimulateNative. Here's my codez:

// and_or_component.jsx
  render: function () {
    var props = {
      className:    'chain and-or',
      onMouseLeave: this._handleMouseLeave,
      onClick:      this._toggleEditing
    };

    return (
      <span {...props}>
        Some content here
      </span>
    );
  },
  _handleMouseLeave: function () {
    this.setState({editing: false});
  },

// and_or_component.jsx.test
  it('sets state to editing:false when the mouse leaves', function () {
    var and_or  = React.TestUtils.renderIntoDocument(<AndOr />);
    var node    = and_or.getDOMNode();

    React.TestUtils.Simulate.click(node);
    React.TestUtils.SimulateNative.mouseOut(node);

    expect(and_or.state.editing).to.equal(false);
  });

Test results:

  AndOrSelector component
    ✔ is defined
    ✔ is not in editing state by default
    ✔ sets state to editing:true when clicked
    ✔ sets state to editing:false when the mouse leaves

@ryanzec
Copy link

ryanzec commented Apr 13, 2015

@brianblocker I tried that using both mouseEnter and mouseOver instead of mouseOut but it still did not trigger my mouseEnter event.

@phoenixbox
Copy link

@ryanzec
If it helps - the difference which worked for me was calling SimulateNative with a DOMNode and not a ReactNode. Pass & fail states listed along with full test case below:

Passed

TestUtils.SimulateNative.mouseOver(chosenListItem.getDOMNode());

Failed

TestUtils.SimulateNative.mouseOver(chosenListItem);

it.only('onMouseOver of an item sets its class to focused', function () {
        let listItems = TestUtils.scryRenderedComponentsWithType(this.component, ListGroupItem);
        let chosenListItem = listItems[0];

        TestUtils.SimulateNative.mouseOver(chosenListItem.getDOMNode());

        assert.isTrue(chosenListItem.getDOMNode().classList.contains('tag-item__focused'));
});
Update:

This seems to also work: ¯\_(ツ)_/¯
TestUtils.Simulate.mouseOver(chosenListItem.getDOMNode());

@Kureev
Copy link

Kureev commented Jul 14, 2015

No update so far? Maybe some workarounds?

@sophiebits
Copy link
Collaborator

@Kureev This was fixed in #1366 in April as you can see a few messages up; it'll be in the 0.14 release. If you search "workaround" on this page you'll see that I also posted a workaround over a year ago.

@Kureev
Copy link

Kureev commented Jul 15, 2015

Sorry, really missed it. Thanks for it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.