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

filterTaps disables all click events in Jest #418

Open
1 task done
jantimon opened this issue Jan 6, 2022 · 7 comments
Open
1 task done

filterTaps disables all click events in Jest #418

jantimon opened this issue Jan 6, 2022 · 7 comments
Assignees

Comments

@jantimon
Copy link

jantimon commented Jan 6, 2022

Describe the bug

the filterTaps option works great in all browser however in JEST it prevents child listeners from working.

I am only guessing but maybe the following line doesn't work well as JEST is not able to get real size measurements:

state.tap = dx <= 3 && dy <= 3

Sandbox or Video

I prepared this CodeSandbox with unit tests.

It contains Demo1 and Demo2:

import { useDrag } from '@use-gesture/react'

export const Demo1 = ({onClick}: {onClick: () => void}) => {
  const bind = useDrag(({ down, movement: [mx, my] }) => {
  }, {

  })
  return <div {...bind()}>
      <button onClick={onClick}>
      click me
      </button>
    </div>
import { useDrag } from '@use-gesture/react'

export const Demo2 = ({onClick}: {onClick: () => void}) => {
  const bind = useDrag(({ down, movement: [mx, my] }) => {
  }, {
    filterTaps: true
  })
  return <div {...bind()}>
      <button onClick={onClick}>
      click me
      </button>
    </div>
}

As you can see the only difference is filterTaps: true.

The result is that the unit test which tries to click the button fails for Demo2:

testResult

Checklist:

@dbismut
Copy link
Collaborator

dbismut commented Jan 6, 2022

Hey, thanks for reporting this.

The filterTaps option checks if the drag is an actual drag or a tap (it does this by checking whether the displacement is greater than 3px). If the drag is a drag, then it prevents the click event to propagate (the click listener is added using capture: true so that events bubble down).

pointerClick(event: MouseEvent) {
if (!this.state.tap) {
event.preventDefault()
event.stopPropagation()
}
}

So I'm not sure how I would be able to solve this. Shouldn't this be a bug in Jest instead?

@jantimon
Copy link
Author

jantimon commented Jan 7, 2022

After some further investigation I found out that fireEvent.click does not trigger mouseDown and mouseUp therefore state.tap is always false

There is a helper library which triggers a full click which works:

import userEvent from '@testing-library/user-event';

userEvent.click()

Could we set state.taps = true by default?

@dbismut
Copy link
Collaborator

dbismut commented Jan 7, 2022

Oh right.

You mean setting state.tap = false on pointerDown then?

I'd have to make sure there's no collaterals.

@jantimon
Copy link
Author

jantimon commented Jan 7, 2022

Rather here:

For normal browsers this shouldn't have any effect as it will be set to a correct value in pointerUp.
However for JEST where there is no pointerUp it would allow to catch click events.

@dbismut
Copy link
Collaborator

dbismut commented Jan 7, 2022

Yes, that's what I meant, but I would have to restore state.tap to a falsy value as soon as the gesture starts, as people might rely on it before pointerUp. In any case it wouldn't make sense to have state.tap = true when the user drags things around.

@jantimon
Copy link
Author

jantimon commented Jan 7, 2022

Oh I see - good point

@marcusstenbeck
Copy link
Contributor

marcusstenbeck commented Aug 4, 2022

For anyone coming here wanting to trigger the tap, try this:

fireEvent.mouseDown(element, { buttons: 1 });
fireEvent.mouseUp(element, { buttons: 1 });

See: MDN - MouseEvent.buttons

The mouseUp() call probably doesn't need the { buttons: 1 }, but let's keep it since it means the mouseDown is followed by a mouseUp with the same button.


This is a more complete example of what's working for me using v10.2.6.

import { fireEvent } from '@testing-library/react';

const click: typeof fireEvent.click = (element, options) => {
  const _options: Record<string, any> = options ?? {};

  if (!_options.buttons) {
    // default to left mouse button
    // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
    _options.buttons = 1;
  }

  return fireEvent.mouseDown(element, _options) && fireEvent.mouseUp(element, _options);
};

Here's how use-gesture tests the tap event: https://github.com/pmndrs/use-gesture/blob/main/test/drag.test.tsx#L232

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

No branches or pull requests

3 participants