1. # `dom-event-testing-library`
    
  2. 
    
  3. A library for unit testing events via high-level interactions, e.g., `pointerdown`,
    
  4. that produce realistic and complete DOM event sequences.
    
  5. 
    
  6. There are number of challenges involved in unit testing modules that work with
    
  7. DOM events.
    
  8. 
    
  9. 1. Gesture recognizers may need to support environments with and without support for
    
  10.    the `PointerEvent` API.
    
  11. 2. Gesture recognizers may need to support various user interaction modes including
    
  12.    mouse, touch, and pen use.
    
  13. 3. Gesture recognizers must account for the actual event sequences browsers produce
    
  14.    (e.g., emulated touch and mouse events.)
    
  15. 4. Gesture recognizers must work with "virtual" events produced by tools like
    
  16.    screen-readers.
    
  17. 
    
  18. Writing unit tests to cover all these scenarios is tedious and error prone. This
    
  19. event testing library is designed to solve these issues by allowing developers to
    
  20. more easily dispatch events in unit tests, and to more reliably test pointer
    
  21. interactions using a high-level API based on `PointerEvent`. Here's a basic example:
    
  22. 
    
  23. ```js
    
  24. import {
    
  25.   describeWithPointerEvent,
    
  26.   testWithPointerType,
    
  27.   createEventTarget,
    
  28.   setPointerEvent,
    
  29.   resetActivePointers
    
  30. } from 'dom-event-testing-library';
    
  31. 
    
  32. describeWithPointerEvent('useTap', hasPointerEvent => {
    
  33.   beforeEach(() => {
    
  34.     // basic PointerEvent mock
    
  35.     setPointerEvent(hasPointerEvent);
    
  36.   });
    
  37. 
    
  38.   afterEach(() => {
    
  39.     // clear active pointers between test runs
    
  40.     resetActivePointers();
    
  41.   });
    
  42. 
    
  43.   // test all the pointer types supported by the environment
    
  44.   testWithPointerType('pointer down', pointerType => {
    
  45.     const ref = createRef(null);
    
  46.     const onTapStart = jest.fn();
    
  47.     render(() => {
    
  48.       useTap(ref, { onTapStart });
    
  49.       return <div ref={ref} />
    
  50.     });
    
  51. 
    
  52.     // create an event target
    
  53.     const target = createEventTarget(ref.current);
    
  54.     // dispatch high-level pointer event
    
  55.     target.pointerdown({ pointerType });
    
  56. 
    
  57.     expect(onTapStart).toBeCalled();
    
  58.   });
    
  59. });
    
  60. ```
    
  61. 
    
  62. This tests the interaction in multiple scenarios. In each case, a realistic DOM
    
  63. event sequence–with complete mock events–is produced. When running in a mock
    
  64. environment without the `PointerEvent` API, the test runs for both `mouse` and
    
  65. `touch` pointer types. When `touch` is the pointer type it produces emulated mouse
    
  66. events. When running in a mock environment with the `PointerEvent` API, the test
    
  67. runs for `mouse`, `touch`, and `pen` pointer types.
    
  68. 
    
  69. It's important to cover all these scenarios because it's very easy to introduce
    
  70. bugs – e.g., double calling of callbacks – if not accounting for emulated mouse
    
  71. events, differences in target capturing between `touch` and `mouse` pointers, and
    
  72. the different semantics of `button` across event APIs.
    
  73. 
    
  74. Default values are provided for the expected native events properties. They can
    
  75. also be customized as needed in a test.
    
  76. 
    
  77. ```js
    
  78. target.pointerdown({
    
  79.   button: 0,
    
  80.   buttons: 1,
    
  81.   pageX: 10,
    
  82.   pageY: 10,
    
  83.   pointerType,
    
  84.   // NOTE: use x,y instead of clientX,clientY
    
  85.   x: 10,
    
  86.   y: 10
    
  87. });
    
  88. ```
    
  89. 
    
  90. Tests that dispatch multiple pointer events will dispatch multi-touch native events
    
  91. on the target.
    
  92. 
    
  93. ```js
    
  94. // first pointer is active
    
  95. target.pointerdown({pointerId: 1, pointerType});
    
  96. // second pointer is active
    
  97. target.pointerdown({pointerId: 2, pointerType});
    
  98. ```