Skip to content

fix: set relatedTarget when the pointer moves between elements - #1333

Open
Om-singhaI wants to merge 1 commit into
testing-library:mainfrom
Om-singhaI:fix/hover-related-target
Open

Om-singhaI wants to merge 1 commit into
testing-library:mainfrom
Om-singhaI:fix/hover-related-target

Conversation

@Om-singhaI

Copy link
Copy Markdown

What

relatedTarget was always null on mouseover, mouseout, mouseenter, mouseleave and the matching pointer events. This sets it to the element the pointer moved to (for out and leave) or came from (for over and enter).

Fixes #1187, fixes #1182. This should also fix #1154.

Why

React reads relatedTarget on mouseout to work out which components get onMouseLeave. With null it assumes the pointer left the page. So if you hover a parent and click a child that only renders while the parent is hovered, the parent's onMouseLeave runs, the child unmounts and the click never lands. The workarounds in the thread are skipHover, which skips the pointer move inside user.click, or fireEvent.click.

How

Mouse.move and Pointer.move now pass nextTarget as relatedTarget for out and leave, and prevTarget for over and enter. If prevTarget was removed from the document it stays null. React ignores a mouseover whose relatedTarget is a node it rendered, and the removed node's mouseout never reaches React, so onMouseEnter would be lost. The first move still starts from document.body, so relatedTarget is body there. Touch Pointer.init and Pointer.release still use null.

Tests:

  • React tests in tests/react/index.tsx for the hover then click children lost target聽#1187 case and for hovering after the previous element was removed
  • relatedTarget checks for mouse and pointer events in tests/pointer/move.ts and tests/convenience/hover.ts

npx jest tests/pointer tests/convenience tests/system tests/react/index.tsx passes all 100 tests. With the source change reverted, the 4 tests for this fail and 96 pass. Without the removed element check, its 2 tests fail. I also wrote small tests for the #1182 example and the case described in #1154 (not in this PR). Both fail on main and pass with this change. No event log snapshots changed.

Checklist

  • N/A Documentation
  • Tests
  • Ready to be merged

`mouseout`, `mouseleave`, `pointerout` and `pointerleave` now carry the
element the pointer moved to, and `mouseover`, `mouseenter`,
`pointerover` and `pointerenter` carry the element it came from.

React reads `relatedTarget` on `mouseout` to decide which components get
`onMouseLeave`. With `null` it treated every move between elements as
the pointer leaving the page, so moving from a parent into its child
called the parent's `onMouseLeave`.

If the element the pointer came from has been removed from the document,
`relatedTarget` stays `null`. React ignores a `mouseover` whose
`relatedTarget` is a node it rendered and waits for the matching
`mouseout`, but the `mouseout` of a removed node never reaches React, so
`onMouseEnter` would be lost.

Fixes testing-library#1187
Fixes testing-library#1182

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hover then click children lost target Support MouseEvent.relatedTarget Mouseleave triggered when hovering again after initial hover

1 participant