react/packages/dom-event-testing-library
Sebastian Markbåge d310d654a7
Avoid meta programming to initialize functions in module scope (#26388)
I'm trying to get rid of all meta programming in the module scope so
that closure can do a better job figuring out cyclic dependencies and
ability to reorder.

This is converting a lot of the patterns that assign functions
conditionally to using function declarations instead.

```
let fn;
if (__DEV__) {
  fn = function() {
    ...
  };
}
```
->
```
function fn() {
  if (__DEV__) {
    ...
  }
}
```
2023-03-14 21:00:22 -04:00
..
__tests__ Update jest printBasicPrototype config (#26142) 2023-02-10 09:58:57 +01:00
README.md Create packages/dom-event-testing-library (#17660) 2019-12-19 16:51:25 +00:00
constants.js [Codemod] Update copyright header to Meta (#25315) 2022-10-18 11:19:24 -04:00
domEnvironment.js Avoid meta programming to initialize functions in module scope (#26388) 2023-03-14 21:00:22 -04:00
domEventSequences.js [Codemod] Update copyright header to Meta (#25315) 2022-10-18 11:19:24 -04:00
domEvents.js [Codemod] Update copyright header to Meta (#25315) 2022-10-18 11:19:24 -04:00
index.js Upgrade prettier (#26081) 2023-01-31 08:25:05 -05:00
package.json Create packages/dom-event-testing-library (#17660) 2019-12-19 16:51:25 +00:00
testHelpers.js [Codemod] Update copyright header to Meta (#25315) 2022-10-18 11:19:24 -04:00
touchStore.js [Codemod] Update copyright header to Meta (#25315) 2022-10-18 11:19:24 -04:00

README.md

dom-event-testing-library

A library for unit testing events via high-level interactions, e.g., pointerdown, that produce realistic and complete DOM event sequences.

There are number of challenges involved in unit testing modules that work with DOM events.

  1. Gesture recognizers may need to support environments with and without support for the PointerEvent API.
  2. Gesture recognizers may need to support various user interaction modes including mouse, touch, and pen use.
  3. Gesture recognizers must account for the actual event sequences browsers produce (e.g., emulated touch and mouse events.)
  4. Gesture recognizers must work with "virtual" events produced by tools like screen-readers.

Writing unit tests to cover all these scenarios is tedious and error prone. This event testing library is designed to solve these issues by allowing developers to more easily dispatch events in unit tests, and to more reliably test pointer interactions using a high-level API based on PointerEvent. Here's a basic example:

import {
  describeWithPointerEvent,
  testWithPointerType,
  createEventTarget,
  setPointerEvent,
  resetActivePointers
} from 'dom-event-testing-library';

describeWithPointerEvent('useTap', hasPointerEvent => {
  beforeEach(() => {
    // basic PointerEvent mock
    setPointerEvent(hasPointerEvent);
  });

  afterEach(() => {
    // clear active pointers between test runs
    resetActivePointers();
  });

  // test all the pointer types supported by the environment
  testWithPointerType('pointer down', pointerType => {
    const ref = createRef(null);
    const onTapStart = jest.fn();
    render(() => {
      useTap(ref, { onTapStart });
      return <div ref={ref} />
    });

    // create an event target
    const target = createEventTarget(ref.current);
    // dispatch high-level pointer event
    target.pointerdown({ pointerType });

    expect(onTapStart).toBeCalled();
  });
});

This tests the interaction in multiple scenarios. In each case, a realistic DOM event sequencewith complete mock eventsis produced. When running in a mock environment without the PointerEvent API, the test runs for both mouse and touch pointer types. When touch is the pointer type it produces emulated mouse events. When running in a mock environment with the PointerEvent API, the test runs for mouse, touch, and pen pointer types.

It's important to cover all these scenarios because it's very easy to introduce bugs e.g., double calling of callbacks if not accounting for emulated mouse events, differences in target capturing between touch and mouse pointers, and the different semantics of button across event APIs.

Default values are provided for the expected native events properties. They can also be customized as needed in a test.

target.pointerdown({
  button: 0,
  buttons: 1,
  pageX: 10,
  pageY: 10,
  pointerType,
  // NOTE: use x,y instead of clientX,clientY
  x: 10,
  y: 10
});

Tests that dispatch multiple pointer events will dispatch multi-touch native events on the target.

// first pointer is active
target.pointerdown({pointerId: 1, pointerType});
// second pointer is active
target.pointerdown({pointerId: 2, pointerType});