[react-events] Press: improve test coverage (#16397)
1. Run the tests in both an environment without PointerEvent and one with PointerEvent. 2. Improve test coverage to include both mouse and touch pointers. 3. Change 'Press' so that it only listens to either pointer events or fallbacks events.
Nicolas Gallagher committed
Aug 15, 2019 at 10:28 UTC
ebd1f5ddb0da7e3626b56614e2b5723debadd839
6 files changed
+858
-1702
packages/react-events/src/dom/Press.js
+33
-32
@@ -95,10 +95,14 @@ type PressEvent = {|
95
shiftKey: boolean,
96
|};
97
98
+const hasPointerEvents =
99
+ typeof window !== 'undefined' && window.PointerEvent !== undefined;
100
+
101
const isMac =
102
typeof window !== 'undefined' && window.navigator != null
103
? /^Mac/.test(window.navigator.platform)
104
: false;
105
+
106
const DEFAULT_PRESS_RETENTION_OFFSET = {
107
bottom: 20,
108
top: 20,
@@ -106,37 +110,32 @@ const DEFAULT_PRESS_RETENTION_OFFSET = {
110
right: 20,
111
};
112
109
-const targetEventTypes = [
110
- 'keydown_active',
111
- // We need to preventDefault on pointerdown for mouse/pen events
112
- // that are in hit target area but not the element area.
113
- 'pointerdown_active',
114
- 'click_active',
115
-];
116
-const rootEventTypes = [
117
- 'click',
118
- 'keyup',
119
- 'pointerup',
120
- 'pointermove',
121
- 'scroll',
122
- 'pointercancel',
123
- // We listen to this here so stopPropagation can
124
- // block other mouseup events used internally
125
- 'mouseup_active',
126
- 'touchend',
127
-];
128
-
129
-// If PointerEvents is not supported (e.g., Safari), also listen to touch and mouse events.
130
-if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
131
- targetEventTypes.push('touchstart', 'mousedown');
132
- rootEventTypes.push(
133
- 'mousemove',
134
- 'touchmove',
135
- 'touchcancel',
136
- // Used as a 'cancel' signal for mouse interactions
137
- 'dragstart',
138
- );
139
-}
113
+const targetEventTypes = hasPointerEvents
114
+ ? [
115
+ 'keydown_active',
116
+ // We need to preventDefault on pointerdown for mouse/pen events
117
+ // that are in hit target area but not the element area.
118
+ 'pointerdown_active',
119
+ 'click_active',
120
+ ]
121
+ : ['keydown_active', 'touchstart', 'mousedown', 'click_active'];
122
+
123
+const rootEventTypes = hasPointerEvents
124
+ ? ['pointerup', 'pointermove', 'pointercancel', 'click', 'keyup', 'scroll']
125
+ : [
126
+ 'click',
127
+ 'keyup',
128
+ 'scroll',
129
+ 'mousemove',
130
+ 'touchmove',
131
+ 'touchcancel',
132
+ // Used as a 'cancel' signal for mouse interactions
133
+ 'dragstart',
134
+ // We listen to this here so stopPropagation can
135
+ // block other mouseup events used internally
136
+ 'mouseup_active',
137
+ 'touchend',
138
+ ];
139
140
function isFunction(obj): boolean {
141
return typeof obj === 'function';
@@ -539,7 +538,7 @@ const pressResponderImpl = {
538
}
539
540
state.shouldPreventClick = false;
542
- if (isPointerEvent || isTouchEvent) {
541
+ if (isTouchEvent) {
542
state.ignoreEmulatedMouseEvents = true;
543
} else if (isKeyboardEvent) {
544
// Ignore unrelated key events
@@ -676,6 +675,7 @@ const pressResponderImpl = {
675
if (state.isPressWithinResponderRegion) {
676
if (isPressed) {
677
const onPressMove = props.onPressMove;
678
+
679
if (isFunction(onPressMove)) {
680
dispatchEvent(
681
event,
@@ -777,6 +777,7 @@ const pressResponderImpl = {
777
);
778
}
779
}
780
+
781
if (state.isPressWithinResponderRegion && button !== 1) {
782
dispatchEvent(
783
event,
packages/react-events/src/dom/__tests__/Focus-test.internal.js
+12
-12
@@ -15,8 +15,8 @@ import {
15
keydown,
16
setPointerEvent,
17
platform,
18
- dispatchPointerPressDown,
19
- dispatchPointerPressRelease,
18
+ dispatchPointerDown,
19
+ dispatchPointerUp,
20
} from '../test-utils';
21
22
let React;
@@ -138,8 +138,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
138
139
it('is called with the correct pointerType: mouse', () => {
140
const target = ref.current;
141
- dispatchPointerPressDown(target, {pointerType: 'mouse'});
142
- dispatchPointerPressRelease(target, {pointerType: 'mouse'});
141
+ dispatchPointerDown(target, {pointerType: 'mouse'});
142
+ dispatchPointerUp(target, {pointerType: 'mouse'});
143
expect(onFocus).toHaveBeenCalledTimes(1);
144
expect(onFocus).toHaveBeenCalledWith(
145
expect.objectContaining({pointerType: 'mouse'}),
@@ -148,8 +148,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
148
149
it('is called with the correct pointerType: touch', () => {
150
const target = ref.current;
151
- dispatchPointerPressDown(target, {pointerType: 'touch'});
152
- dispatchPointerPressRelease(target, {pointerType: 'touch'});
151
+ dispatchPointerDown(target, {pointerType: 'touch'});
152
+ dispatchPointerUp(target, {pointerType: 'touch'});
153
expect(onFocus).toHaveBeenCalledTimes(1);
154
expect(onFocus).toHaveBeenCalledWith(
155
expect.objectContaining({pointerType: 'touch'}),
@@ -159,8 +159,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
159
if (hasPointerEvents) {
160
it('is called with the correct pointerType: pen', () => {
161
const target = ref.current;
162
- dispatchPointerPressDown(target, {pointerType: 'pen'});
163
- dispatchPointerPressRelease(target, {pointerType: 'pen'});
162
+ dispatchPointerDown(target, {pointerType: 'pen'});
163
+ dispatchPointerUp(target, {pointerType: 'pen'});
164
expect(onFocus).toHaveBeenCalledTimes(1);
165
expect(onFocus).toHaveBeenCalledWith(
166
expect.objectContaining({pointerType: 'pen'}),
@@ -278,7 +278,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
278
expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
279
expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
280
// then use pointer on the target, focus should no longer be visible
281
- dispatchPointerPressDown(target);
281
+ dispatchPointerDown(target);
282
expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
283
expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
284
// onFocusVisibleChange should not be called again
@@ -288,9 +288,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
288
289
it('is not called after "focus" and "blur" events without keyboard', () => {
290
const target = ref.current;
291
- dispatchPointerPressDown(target);
292
- dispatchPointerPressRelease(target);
293
- dispatchPointerPressDown(container);
291
+ dispatchPointerDown(target);
292
+ dispatchPointerUp(target);
293
+ dispatchPointerDown(container);
294
target.dispatchEvent(blur({relatedTarget: container}));
295
expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
296
});
packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js
+6
-6
@@ -14,8 +14,8 @@ import {
14
focus,
15
keydown,
16
setPointerEvent,
17
- dispatchPointerPressDown,
18
- dispatchPointerPressRelease,
17
+ dispatchPointerDown,
18
+ dispatchPointerUp,
19
} from '../test-utils';
20
21
let React;
@@ -203,7 +203,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
203
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
204
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
205
// then use pointer on the next target, focus should no longer be visible
206
- dispatchPointerPressDown(innerTarget2);
206
+ dispatchPointerDown(innerTarget2);
207
innerTarget1.dispatchEvent(blur({relatedTarget: innerTarget2}));
208
innerTarget2.dispatchEvent(focus());
209
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
@@ -215,7 +215,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
215
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(3);
216
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
217
// then use pointer on the target, focus should no longer be visible
218
- dispatchPointerPressDown(innerTarget1);
218
+ dispatchPointerDown(innerTarget1);
219
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
220
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
221
// onFocusVisibleChange should not be called again
@@ -225,8 +225,8 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
225
226
it('is not called after "focus" and "blur" events without keyboard', () => {
227
const innerTarget = innerRef.current;
228
- dispatchPointerPressDown(innerTarget);
229
- dispatchPointerPressRelease(innerTarget);
228
+ dispatchPointerDown(innerTarget);
229
+ dispatchPointerUp(innerTarget);
230
innerTarget.dispatchEvent(blur({relatedTarget: container}));
231
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
232
});
packages/react-events/src/dom/__tests__/Hover-test.internal.js
+4
-5
@@ -213,7 +213,8 @@ describe.each(table)('Hover responder', hasPointerEvents => {
213
214
const target = ref.current;
215
dispatchPointerHoverEnter(target);
216
- dispatchPointerHoverMove(target, {from: {x: 0, y: 0}, to: {x: 1, y: 1}});
216
+ dispatchPointerHoverMove(target, {x: 0, y: 0});
217
+ dispatchPointerHoverMove(target, {x: 1, y: 1});
218
expect(onHoverMove).toHaveBeenCalledTimes(2);
219
expect(onHoverMove).toHaveBeenCalledWith(
220
expect.objectContaining({type: 'hovermove'}),
@@ -317,10 +318,8 @@ describe.each(table)('Hover responder', hasPointerEvents => {
318
const target = ref.current;
319
320
dispatchPointerHoverEnter(target, {x: 10, y: 10});
320
- dispatchPointerHoverMove(target, {
321
- from: {x: 10, y: 10},
322
- to: {x: 20, y: 20},
323
- });
321
+ dispatchPointerHoverMove(target, {x: 10, y: 10});
322
+ dispatchPointerHoverMove(target, {x: 20, y: 20});
323
dispatchPointerHoverExit(target, {x: 20, y: 20});
324
325
expect(eventLog).toEqual([
packages/react-events/src/dom/__tests__/Press-test.internal.js
+646
-1571
@@ -9,6 +9,21 @@
9
10
'use strict';
11
12
+import {
13
+ click,
14
+ dispatchPointerCancel,
15
+ dispatchPointerDown,
16
+ dispatchPointerUp,
17
+ dispatchPointerHoverMove,
18
+ dispatchPointerMove,
19
+ keydown,
20
+ keyup,
21
+ scroll,
22
+ pointerdown,
23
+ pointerup,
24
+ setPointerEvent,
25
+} from '../test-utils';
26
+
27
let React;
28
let ReactFeatureFlags;
29
let ReactDOM;
@@ -16,39 +31,9 @@ let PressResponder;
31
let usePressResponder;
32
let Scheduler;
33
19
-const createEvent = (type, data) => {
20
- const event = document.createEvent('CustomEvent');
21
- event.initCustomEvent(type, true, true);
22
- if (data != null) {
23
- Object.entries(data).forEach(([key, value]) => {
24
- event[key] = value;
25
- });
26
- }
27
- return event;
28
-};
29
-
30
-function createTouchEvent(type, id, data) {
31
- return createEvent(type, {
32
- changedTouches: [
33
- {
34
- ...data,
35
- identifier: id,
36
- },
37
- ],
38
- targetTouches: [
39
- {
40
- ...data,
41
- identifier: id,
42
- },
43
- ],
44
- });
45
-}
46
-
47
-const createKeyboardEvent = (type, data) => {
48
- return createEvent(type, data);
49
-};
50
-
51
-function init() {
34
+function initializeModules(hasPointerEvents) {
35
+ jest.resetModules();
36
+ setPointerEvent(hasPointerEvents);
37
ReactFeatureFlags = require('shared/ReactFeatureFlags');
38
ReactFeatureFlags.enableFlareAPI = true;
39
React = require('react');
@@ -58,12 +43,23 @@ function init() {
43
Scheduler = require('scheduler');
44
}
45
61
-describe('Event responder: Press', () => {
46
+function removePressMoveStrings(eventString) {
47
+ if (eventString === 'onPressMove') {
48
+ return false;
49
+ }
50
+ return true;
51
+}
52
+
53
+const forcePointerEvents = true;
54
+const environmentTable = [[forcePointerEvents], [!forcePointerEvents]];
55
+
56
+const pointerTypesTable = [['mouse'], ['touch']];
57
+
58
+describe.each(environmentTable)('Press responder', hasPointerEvents => {
59
let container;
60
61
beforeEach(() => {
65
- jest.resetModules();
66
- init();
62
+ initializeModules(hasPointerEvents);
63
container = document.createElement('div');
64
document.body.appendChild(container);
65
});
@@ -92,11 +88,13 @@ describe('Event responder: Press', () => {
88
return <div ref={ref} listeners={listener} />;
89
};
90
ReactDOM.render(<Component />, container);
91
+ document.elementFromPoint = () => ref.current;
92
});
93
97
- it('prevents custom events being dispatched', () => {
98
- ref.current.dispatchEvent(createEvent('pointerdown'));
99
- ref.current.dispatchEvent(createEvent('pointerup'));
94
+ it('does not call callbacks', () => {
95
+ const target = ref.current;
96
+ dispatchPointerDown(target);
97
+ dispatchPointerUp(target);
98
expect(onPressStart).not.toBeCalled();
99
expect(onPress).not.toBeCalled();
100
expect(onPressEnd).not.toBeCalled();
@@ -116,27 +114,22 @@ describe('Event responder: Press', () => {
114
return <div ref={ref} listeners={listener} />;
115
};
116
ReactDOM.render(<Component />, container);
117
+ document.elementFromPoint = () => ref.current;
118
});
119
121
- it('is called after "pointerdown" event', () => {
122
- ref.current.dispatchEvent(
123
- createEvent('pointerdown', {pointerType: 'pen'}),
124
- );
125
- ref.current.dispatchEvent(
126
- createTouchEvent('touchstart', 0, {
127
- target: ref.current,
128
- }),
129
- );
130
- expect(onPressStart).toHaveBeenCalledTimes(1);
131
- expect(onPressStart).toHaveBeenCalledWith(
132
- expect.objectContaining({pointerType: 'pen', type: 'pressstart'}),
133
- );
134
- });
120
+ it.each(pointerTypesTable)(
121
+ 'is called after pointer down: %s',
122
+ pointerType => {
123
+ dispatchPointerDown(ref.current, {pointerType});
124
+ expect(onPressStart).toHaveBeenCalledTimes(1);
125
+ expect(onPressStart).toHaveBeenCalledWith(
126
+ expect.objectContaining({pointerType, type: 'pressstart'}),
127
+ );
128
+ },
129
+ );
130
136
- it('is called after auxillary-button "pointerdown" event', () => {
137
- ref.current.dispatchEvent(
138
- createEvent('pointerdown', {button: 1, pointerType: 'mouse'}),
139
- );
131
+ it('is called after auxillary-button pointer down', () => {
132
+ dispatchPointerDown(ref.current, {button: 1, pointerType: 'mouse'});
133
expect(onPressStart).toHaveBeenCalledTimes(1);
134
expect(onPressStart).toHaveBeenCalledWith(
135
expect.objectContaining({
@@ -148,64 +141,38 @@ describe('Event responder: Press', () => {
141
});
142
143
it('is not called after "pointermove" following auxillary-button press', () => {
151
- ref.current.getBoundingClientRect = () => ({
144
+ const target = ref.current;
145
+ target.getBoundingClientRect = () => ({
146
top: 0,
147
left: 0,
148
bottom: 100,
149
right: 100,
150
});
157
- ref.current.dispatchEvent(
158
- createEvent('pointerdown', {
159
- button: 1,
160
- pointerType: 'mouse',
161
- clientX: 50,
162
- clientY: 50,
163
- }),
164
- );
165
- ref.current.dispatchEvent(
166
- createEvent('pointerup', {
167
- button: 1,
168
- pointerType: 'mouse',
169
- clientX: 50,
170
- clientY: 50,
171
- }),
172
- );
173
- container.dispatchEvent(
174
- createEvent('pointermove', {
175
- button: 1,
176
- pointerType: 'mouse',
177
- clientX: 110,
178
- clientY: 110,
179
- }),
180
- );
181
- container.dispatchEvent(
182
- createEvent('pointermove', {
183
- button: 1,
184
- pointerType: 'mouse',
185
- clientX: 50,
186
- clientY: 50,
187
- }),
188
- );
189
- expect(onPressStart).toHaveBeenCalledTimes(1);
190
- });
191
-
192
- it('ignores browser emulated events', () => {
193
- ref.current.dispatchEvent(createEvent('pointerdown'));
194
- ref.current.dispatchEvent(createEvent('touchstart'));
195
- ref.current.dispatchEvent(createEvent('mousedown'));
151
+ dispatchPointerDown(target, {
152
+ button: 1,
153
+ pointerType: 'mouse',
154
+ });
155
+ dispatchPointerUp(target, {
156
+ button: 1,
157
+ pointerType: 'mouse',
158
+ });
159
+ dispatchPointerHoverMove(target, {x: 110, y: 110});
160
+ dispatchPointerHoverMove(target, {x: 50, y: 50});
161
expect(onPressStart).toHaveBeenCalledTimes(1);
162
});
163
164
it('ignores any events not caused by primary/auxillary-click or touch/pen contact', () => {
200
- ref.current.dispatchEvent(createEvent('pointerdown', {button: 5}));
201
- ref.current.dispatchEvent(createEvent('mousedown', {button: 2}));
165
+ const target = ref.current;
166
+ dispatchPointerDown(target, {button: 2});
167
+ dispatchPointerDown(target, {button: 5});
168
expect(onPressStart).toHaveBeenCalledTimes(0);
169
});
170
171
it('is called once after "keydown" events for Enter', () => {
206
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
207
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
208
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
172
+ const target = ref.current;
173
+ target.dispatchEvent(keydown({key: 'Enter'}));
174
+ target.dispatchEvent(keydown({key: 'Enter'}));
175
+ target.dispatchEvent(keydown({key: 'Enter'}));
176
expect(onPressStart).toHaveBeenCalledTimes(1);
177
expect(onPressStart).toHaveBeenCalledWith(
178
expect.objectContaining({pointerType: 'keyboard', type: 'pressstart'}),
@@ -213,14 +180,11 @@ describe('Event responder: Press', () => {
180
});
181
182
it('is called once after "keydown" events for Spacebar', () => {
183
+ const target = ref.current;
184
const preventDefault = jest.fn();
217
- ref.current.dispatchEvent(
218
- createKeyboardEvent('keydown', {key: ' ', preventDefault}),
219
- );
185
+ target.dispatchEvent(keydown({key: ' ', preventDefault}));
186
expect(preventDefault).toBeCalled();
221
- ref.current.dispatchEvent(createKeyboardEvent('keypress', {key: ' '}));
222
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: ' '}));
223
- ref.current.dispatchEvent(createKeyboardEvent('keypress', {key: ' '}));
187
+ target.dispatchEvent(keydown({key: ' ', preventDefault}));
188
expect(onPressStart).toHaveBeenCalledTimes(1);
189
expect(onPressStart).toHaveBeenCalledWith(
190
expect.objectContaining({
@@ -231,34 +195,9 @@ describe('Event responder: Press', () => {
195
});
196
197
it('is not called after "keydown" for other keys', () => {
234
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'a'}));
198
+ ref.current.dispatchEvent(keydown({key: 'a'}));
199
expect(onPressStart).not.toBeCalled();
200
});
237
-
238
- // No PointerEvent fallbacks
239
- it('is called after "mousedown" event', () => {
240
- ref.current.dispatchEvent(
241
- createEvent('mousedown', {
242
- button: 0,
243
- }),
244
- );
245
- expect(onPressStart).toHaveBeenCalledTimes(1);
246
- expect(onPressStart).toHaveBeenCalledWith(
247
- expect.objectContaining({pointerType: 'mouse', type: 'pressstart'}),
248
- );
249
- });
250
-
251
- it('is called after "touchstart" event', () => {
252
- ref.current.dispatchEvent(
253
- createTouchEvent('touchstart', 0, {
254
- target: ref.current,
255
- }),
256
- );
257
- expect(onPressStart).toHaveBeenCalledTimes(1);
258
- expect(onPressStart).toHaveBeenCalledWith(
259
- expect.objectContaining({pointerType: 'touch', type: 'pressstart'}),
260
- );
261
- });
201
});
202
203
describe('onPressEnd', () => {
@@ -274,36 +213,26 @@ describe('Event responder: Press', () => {
213
return <div ref={ref} listeners={listener} />;
214
};
215
ReactDOM.render(<Component />, container);
216
+ document.elementFromPoint = () => ref.current;
217
});
218
279
- it('is called after "pointerup" event', () => {
280
- ref.current.dispatchEvent(
281
- createEvent('pointerdown', {pointerType: 'pen'}),
282
- );
283
- ref.current.dispatchEvent(
284
- createTouchEvent('touchstart', 0, {
285
- target: ref.current,
286
- }),
287
- );
288
- ref.current.dispatchEvent(
289
- createTouchEvent('touchend', 0, {
290
- target: ref.current,
291
- }),
292
- );
293
- ref.current.dispatchEvent(createEvent('pointerup', {pointerType: 'pen'}));
294
- expect(onPressEnd).toHaveBeenCalledTimes(1);
295
- expect(onPressEnd).toHaveBeenCalledWith(
296
- expect.objectContaining({pointerType: 'pen', type: 'pressend'}),
297
- );
298
- });
219
+ it.each(pointerTypesTable)(
220
+ 'is called after pointer up: %s',
221
+ pointerType => {
222
+ const target = ref.current;
223
+ dispatchPointerDown(target, {pointerType});
224
+ dispatchPointerUp(target, {pointerType});
225
+ expect(onPressEnd).toHaveBeenCalledTimes(1);
226
+ expect(onPressEnd).toHaveBeenCalledWith(
227
+ expect.objectContaining({pointerType, type: 'pressend'}),
228
+ );
229
+ },
230
+ );
231
300
- it('is called after auxillary-button "pointerup" event', () => {
301
- ref.current.dispatchEvent(
302
- createEvent('pointerdown', {button: 1, pointerType: 'mouse'}),
303
- );
304
- ref.current.dispatchEvent(
305
- createEvent('pointerup', {button: 1, pointerType: 'mouse'}),
306
- );
232
+ it('is called after auxillary-button pointer up', () => {
233
+ const target = ref.current;
234
+ dispatchPointerDown(target, {button: 1, pointerType: 'mouse'});
235
+ dispatchPointerUp(target, {button: 1, pointerType: 'mouse'});
236
expect(onPressEnd).toHaveBeenCalledTimes(1);
237
expect(onPressEnd).toHaveBeenCalledWith(
238
expect.objectContaining({
@@ -314,37 +243,12 @@ describe('Event responder: Press', () => {
243
);
244
});
245
317
- it('ignores browser emulated events', () => {
318
- ref.current.dispatchEvent(
319
- createEvent('pointerdown', {pointerType: 'touch'}),
320
- );
321
- ref.current.dispatchEvent(
322
- createTouchEvent('touchstart', 0, {
323
- target: ref.current,
324
- }),
325
- );
326
- ref.current.dispatchEvent(
327
- createEvent('pointerup', {pointerType: 'touch'}),
328
- );
329
- ref.current.dispatchEvent(
330
- createTouchEvent('touchend', 0, {
331
- target: ref.current,
332
- }),
333
- );
334
- ref.current.dispatchEvent(createEvent('mousedown'));
335
- ref.current.dispatchEvent(createEvent('mouseup'));
336
- ref.current.dispatchEvent(createEvent('click'));
337
- expect(onPressEnd).toHaveBeenCalledTimes(1);
338
- expect(onPressEnd).toHaveBeenCalledWith(
339
- expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
340
- );
341
- });
342
-
246
it('is called after "keyup" event for Enter', () => {
344
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
247
+ const target = ref.current;
248
+ target.dispatchEvent(keydown({key: 'Enter'}));
249
// click occurs before keyup
346
- ref.current.dispatchEvent(createKeyboardEvent('click'));
347
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
250
+ target.dispatchEvent(click());
251
+ target.dispatchEvent(keyup({key: 'Enter'}));
252
expect(onPressEnd).toHaveBeenCalledTimes(1);
253
expect(onPressEnd).toHaveBeenCalledWith(
254
expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
@@ -352,8 +256,9 @@ describe('Event responder: Press', () => {
256
});
257
258
it('is called after "keyup" event for Spacebar', () => {
355
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: ' '}));
356
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: ' '}));
259
+ const target = ref.current;
260
+ target.dispatchEvent(keydown({key: ' '}));
261
+ target.dispatchEvent(keyup({key: ' '}));
262
expect(onPressEnd).toHaveBeenCalledTimes(1);
263
expect(onPressEnd).toHaveBeenCalledWith(
264
expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
@@ -361,15 +266,17 @@ describe('Event responder: Press', () => {
266
});
267
268
it('is not called after "keyup" event for other keys', () => {
364
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
365
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'a'}));
269
+ const target = ref.current;
270
+ target.dispatchEvent(keydown({key: 'Enter'}));
271
+ target.dispatchEvent(keyup({key: 'a'}));
272
expect(onPressEnd).not.toBeCalled();
273
});
274
275
it('is called with keyboard modifiers', () => {
370
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
371
- ref.current.dispatchEvent(
372
- createKeyboardEvent('keyup', {
276
+ const target = ref.current;
277
+ target.dispatchEvent(keydown({key: 'Enter'}));
278
+ target.dispatchEvent(
279
+ keyup({
280
key: 'Enter',
281
metaKey: true,
282
ctrlKey: true,
@@ -388,41 +295,6 @@ describe('Event responder: Press', () => {
295
}),
296
);
297
});
391
-
392
- // No PointerEvent fallbacks
393
- it('is called after "mouseup" event', () => {
394
- ref.current.dispatchEvent(
395
- createEvent('mousedown', {
396
- button: 0,
397
- }),
398
- );
399
- ref.current.dispatchEvent(
400
- createEvent('mouseup', {
401
- button: 0,
402
- }),
403
- );
404
- expect(onPressEnd).toHaveBeenCalledTimes(1);
405
- expect(onPressEnd).toHaveBeenCalledWith(
406
- expect.objectContaining({pointerType: 'mouse', type: 'pressend'}),
407
- );
408
- });
409
- it('is called after "touchend" event', () => {
410
- document.elementFromPoint = () => ref.current;
411
- ref.current.dispatchEvent(
412
- createTouchEvent('touchstart', 0, {
413
- target: ref.current,
414
- }),
415
- );
416
- ref.current.dispatchEvent(
417
- createTouchEvent('touchend', 0, {
418
- target: ref.current,
419
- }),
420
- );
421
- expect(onPressEnd).toHaveBeenCalledTimes(1);
422
- expect(onPressEnd).toHaveBeenCalledWith(
423
- expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
424
- );
425
- });
298
});
299
300
describe('onPressChange', () => {
@@ -438,22 +310,27 @@ describe('Event responder: Press', () => {
310
return <div ref={ref} listeners={listener} />;
311
};
312
ReactDOM.render(<Component />, container);
313
+ document.elementFromPoint = () => ref.current;
314
});
315
443
- it('is called after "pointerdown" and "pointerup" events', () => {
444
- ref.current.dispatchEvent(createEvent('pointerdown'));
445
- expect(onPressChange).toHaveBeenCalledTimes(1);
446
- expect(onPressChange).toHaveBeenCalledWith(true);
447
- ref.current.dispatchEvent(createEvent('pointerup'));
448
- expect(onPressChange).toHaveBeenCalledTimes(2);
449
- expect(onPressChange).toHaveBeenCalledWith(false);
450
- });
316
+ it.each(pointerTypesTable)(
317
+ 'is called after pointer down and up: %s',
318
+ pointerType => {
319
+ const target = ref.current;
320
+ dispatchPointerDown(target, {pointerType});
321
+ expect(onPressChange).toHaveBeenCalledTimes(1);
322
+ expect(onPressChange).toHaveBeenCalledWith(true);
323
+ dispatchPointerUp(target, {pointerType});
324
+ expect(onPressChange).toHaveBeenCalledTimes(2);
325
+ expect(onPressChange).toHaveBeenCalledWith(false);
326
+ },
327
+ );
328
329
it('is called after valid "keydown" and "keyup" events', () => {
453
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
330
+ ref.current.dispatchEvent(keydown({key: 'Enter'}));
331
expect(onPressChange).toHaveBeenCalledTimes(1);
332
expect(onPressChange).toHaveBeenCalledWith(true);
456
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
333
+ ref.current.dispatchEvent(keyup({key: 'Enter'}));
334
expect(onPressChange).toHaveBeenCalledTimes(2);
335
expect(onPressChange).toHaveBeenCalledWith(false);
336
});
@@ -478,58 +355,33 @@ describe('Event responder: Press', () => {
355
bottom: 100,
356
right: 100,
357
});
358
+ document.elementFromPoint = () => ref.current;
359
});
360
483
- it('is called after "pointerup" event', () => {
484
- ref.current.dispatchEvent(
485
- createEvent('pointerdown', {pointerType: 'pen'}),
486
- );
487
- ref.current.dispatchEvent(
488
- createTouchEvent('touchstart', 0, {
489
- target: ref.current,
490
- clientX: 0,
491
- clientY: 0,
492
- }),
493
- );
494
- ref.current.dispatchEvent(
495
- createTouchEvent('touchend', 0, {
496
- target: ref.current,
497
- clientX: 0,
498
- clientY: 0,
499
- }),
500
- );
501
- ref.current.dispatchEvent(
502
- createEvent('pointerup', {
503
- pointerType: 'pen',
504
- clientX: 0,
505
- clientY: 0,
506
- }),
507
- );
508
- expect(onPress).toHaveBeenCalledTimes(1);
509
- expect(onPress).toHaveBeenCalledWith(
510
- expect.objectContaining({pointerType: 'pen', type: 'press'}),
511
- );
512
- });
361
+ it.each(pointerTypesTable)(
362
+ 'is called after pointer up: %s',
363
+ pointerType => {
364
+ const target = ref.current;
365
+ dispatchPointerDown(target, {pointerType});
366
+ dispatchPointerUp(target, {pointerType, x: 10, y: 10});
367
+ expect(onPress).toHaveBeenCalledTimes(1);
368
+ expect(onPress).toHaveBeenCalledWith(
369
+ expect.objectContaining({pointerType, type: 'press'}),
370
+ );
371
+ },
372
+ );
373
374
it('is not called after auxillary-button press', () => {
515
- const Component = () => {
516
- const listener = usePressResponder({
517
- onPress,
518
- });
519
- return <div ref={ref} listeners={listener} />;
520
- };
521
- ReactDOM.render(<Component />, container);
522
-
523
- ref.current.dispatchEvent(createEvent('pointerdown', {button: 1}));
524
- ref.current.dispatchEvent(
525
- createEvent('pointerup', {button: 1, clientX: 10, clientY: 10}),
526
- );
375
+ const target = ref.current;
376
+ dispatchPointerDown(target, {button: 1, pointerType: 'mouse'});
377
+ dispatchPointerUp(target, {button: 1, pointerType: 'mouse'});
378
expect(onPress).not.toHaveBeenCalled();
379
});
380
381
it('is called after valid "keyup" event', () => {
531
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
532
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
382
+ const target = ref.current;
383
+ target.dispatchEvent(keydown({key: 'Enter'}));
384
+ target.dispatchEvent(keyup({key: 'Enter'}));
385
expect(onPress).toHaveBeenCalledTimes(1);
386
expect(onPress).toHaveBeenCalledWith(
387
expect.objectContaining({pointerType: 'keyboard', type: 'press'}),
@@ -545,26 +397,21 @@ describe('Event responder: Press', () => {
397
return <input ref={inputRef} listeners={listener} />;
398
};
399
ReactDOM.render(<Component />, container);
548
- inputRef.current.dispatchEvent(
549
- createKeyboardEvent('keydown', {key: 'Enter'}),
550
- );
551
- inputRef.current.dispatchEvent(
552
- createKeyboardEvent('keyup', {key: 'Enter'}),
553
- );
554
- inputRef.current.dispatchEvent(
555
- createKeyboardEvent('keydown', {key: ' '}),
556
- );
557
- inputRef.current.dispatchEvent(createKeyboardEvent('keyup', {key: ' '}));
400
+ const target = inputRef.current;
401
+ target.dispatchEvent(keydown({key: 'Enter'}));
402
+ target.dispatchEvent(keyup({key: 'Enter'}));
403
+ target.dispatchEvent(keydown({key: ' '}));
404
+ target.dispatchEvent(keyup({key: ' '}));
405
expect(onPress).not.toBeCalled();
406
});
407
408
it('is called with modifier keys', () => {
562
- ref.current.dispatchEvent(
563
- createEvent('pointerdown', {metaKey: true, pointerType: 'mouse'}),
564
- );
565
- ref.current.dispatchEvent(
566
- createEvent('pointerup', {metaKey: true, pointerType: 'mouse'}),
567
- );
409
+ const target = ref.current;
410
+ dispatchPointerDown(target, {metaKey: true, pointerType: 'mouse'});
411
+ dispatchPointerUp(target, {
412
+ metaKey: true,
413
+ pointerType: 'mouse',
414
+ });
415
expect(onPress).toHaveBeenCalledWith(
416
expect.objectContaining({
417
pointerType: 'mouse',
@@ -596,28 +443,19 @@ describe('Event responder: Press', () => {
443
bottom: 0,
444
top: 0,
445
});
599
- buttonRef.current.dispatchEvent(
600
- createEvent('pointerdown', {pointerType: 'mouse'}),
601
- );
602
- buttonRef.current.dispatchEvent(
603
- createEvent('pointerup', {pointerType: 'mouse'}),
604
- );
446
+ const target = buttonRef.current;
447
+ dispatchPointerDown(target, {pointerType: 'mouse'});
448
+ dispatchPointerUp(target, {pointerType: 'mouse'});
449
expect(onPress).toBeCalled();
450
});
607
-
608
- // No PointerEvent fallbacks
609
- // TODO: jsdom missing APIs
610
- // it('is called after "touchend" event', () => {
611
- // ref.current.dispatchEvent(createEvent('touchstart'));
612
- // ref.current.dispatchEvent(createEvent('touchend'));
613
- // expect(onPress).toHaveBeenCalledTimes(1);
614
- // });
451
});
452
453
describe('onPressMove', () => {
618
- it('is called after "pointermove"', () => {
619
- const onPressMove = jest.fn();
620
- const ref = React.createRef();
454
+ let onPressMove, ref;
455
+
456
+ beforeEach(() => {
457
+ onPressMove = jest.fn();
458
+ ref = React.createRef();
459
const Component = () => {
460
const listener = usePressResponder({
461
onPressMove,
@@ -625,102 +463,90 @@ describe('Event responder: Press', () => {
463
return <div ref={ref} listeners={listener} />;
464
};
465
ReactDOM.render(<Component />, container);
628
-
466
ref.current.getBoundingClientRect = () => ({
467
top: 0,
468
left: 0,
469
bottom: 100,
470
right: 100,
471
});
635
- ref.current.dispatchEvent(
636
- createEvent('pointerdown', {pointerType: 'mouse'}),
637
- );
638
- ref.current.dispatchEvent(
639
- createEvent('pointermove', {
640
- pointerType: 'mouse',
641
- clientX: 10,
642
- clientY: 10,
643
- }),
644
- );
645
- expect(onPressMove).toHaveBeenCalledTimes(1);
646
- expect(onPressMove).toHaveBeenCalledWith(
647
- expect.objectContaining({pointerType: 'mouse', type: 'pressmove'}),
648
- );
472
+ document.elementFromPoint = () => ref.current;
473
});
474
651
- it('is not called if "pointermove" occurs during keyboard press', () => {
652
- const onPressMove = jest.fn();
653
- const ref = React.createRef();
654
- const Component = () => {
655
- const listener = usePressResponder({
656
- onPressMove,
475
+ it.each(pointerTypesTable)(
476
+ 'is called after pointer move: %s',
477
+ pointerType => {
478
+ const target = ref.current;
479
+ target.getBoundingClientRect = () => ({
480
+ top: 0,
481
+ left: 0,
482
+ bottom: 100,
483
+ right: 100,
484
});
658
- return <div ref={ref} listeners={listener} />;
659
- };
660
- ReactDOM.render(<Component />, container);
485
+ dispatchPointerDown(target, {pointerType});
486
+ dispatchPointerMove(target, {
487
+ pointerType,
488
+ x: 10,
489
+ y: 10,
490
+ });
491
+ dispatchPointerMove(target, {
492
+ pointerType,
493
+ x: 20,
494
+ y: 20,
495
+ });
496
+ expect(onPressMove).toHaveBeenCalledTimes(2);
497
+ expect(onPressMove).toHaveBeenCalledWith(
498
+ expect.objectContaining({pointerType, type: 'pressmove'}),
499
+ );
500
+ },
501
+ );
502
662
- ref.current.getBoundingClientRect = () => ({
503
+ it('is not called if pointer move occurs during keyboard press', () => {
504
+ const target = ref.current;
505
+ target.getBoundingClientRect = () => ({
506
top: 0,
507
left: 0,
508
bottom: 100,
509
right: 100,
510
});
668
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
669
- ref.current.dispatchEvent(
670
- createEvent('pointermove', {
671
- pointerType: 'mouse',
672
- clientX: 10,
673
- clientY: 10,
674
- }),
675
- );
511
+ target.dispatchEvent(keydown({key: 'Enter'}));
512
+ dispatchPointerMove(target, {
513
+ button: -1,
514
+ pointerType: 'mouse',
515
+ x: 10,
516
+ y: 10,
517
+ });
518
expect(onPressMove).not.toBeCalled();
519
});
520
+ });
521
679
- it('ignores browser emulated events', () => {
680
- const onPressMove = jest.fn();
681
- const ref = React.createRef();
522
+ describe.each(pointerTypesTable)('press with movement: %s', pointerType => {
523
+ let events, ref, outerRef;
524
+
525
+ beforeEach(() => {
526
+ events = [];
527
+ ref = React.createRef();
528
+ outerRef = React.createRef();
529
+ const createEventHandler = msg => () => {
530
+ events.push(msg);
531
+ };
532
const Component = () => {
533
const listener = usePressResponder({
684
- onPressMove,
534
+ onPress: createEventHandler('onPress'),
535
+ onPressChange: createEventHandler('onPressChange'),
536
+ onPressMove: createEventHandler('onPressMove'),
537
+ onPressStart: createEventHandler('onPressStart'),
538
+ onPressEnd: createEventHandler('onPressEnd'),
539
});
686
- return <div ref={ref} listeners={listener} />;
540
+ return (
541
+ <div ref={outerRef}>
542
+ <div ref={ref} listeners={listener} />
543
+ </div>
544
+ );
545
};
546
ReactDOM.render(<Component />, container);
689
-
690
- ref.current.getBoundingClientRect = () => ({
691
- top: 0,
692
- left: 0,
693
- bottom: 100,
694
- right: 100,
695
- });
696
- ref.current.dispatchEvent(
697
- createEvent('pointerdown', {pointerType: 'touch'}),
698
- );
699
- ref.current.dispatchEvent(
700
- createTouchEvent('touchstart', 0, {
701
- target: ref.current,
702
- }),
703
- );
704
- ref.current.dispatchEvent(
705
- createEvent('pointermove', {
706
- pointerType: 'touch',
707
- clientX: 10,
708
- clientY: 10,
709
- }),
710
- );
711
- ref.current.dispatchEvent(
712
- createTouchEvent('touchmove', 0, {
713
- target: ref.current,
714
- clientX: 10,
715
- clientY: 10,
716
- }),
717
- );
718
- ref.current.dispatchEvent(createEvent('mousemove'));
719
- expect(onPressMove).toHaveBeenCalledTimes(1);
547
+ document.elementFromPoint = () => ref.current;
548
});
721
- });
549
723
- describe('press with movement (pointer events)', () => {
550
const rectMock = {
551
width: 100,
552
height: 100,
@@ -732,12 +558,12 @@ describe('Event responder: Press', () => {
558
const pressRectOffset = 20;
559
const getBoundingClientRectMock = () => rectMock;
560
const coordinatesInside = {
735
- clientX: rectMock.left - pressRectOffset,
736
- clientY: rectMock.top - pressRectOffset,
561
+ x: rectMock.left - pressRectOffset,
562
+ y: rectMock.top - pressRectOffset,
563
};
564
const coordinatesOutside = {
739
- clientX: rectMock.left - pressRectOffset - 1,
740
- clientY: rectMock.top - pressRectOffset - 1,
565
+ x: rectMock.left - pressRectOffset - 1,
566
+ y: rectMock.top - pressRectOffset - 1,
567
};
568
569
describe('within bounds of hit rect', () => {
@@ -749,32 +575,12 @@ describe('Event responder: Press', () => {
575
* └──────────────────┘
576
*/
577
it('"onPress*" events are called immediately', () => {
752
- let events = [];
753
- const ref = React.createRef();
754
- const createEventHandler = msg => () => {
755
- events.push(msg);
756
- };
757
-
758
- const Component = () => {
759
- const listener = usePressResponder({
760
- onPress: createEventHandler('onPress'),
761
- onPressChange: createEventHandler('onPressChange'),
762
- onPressMove: createEventHandler('onPressMove'),
763
- onPressStart: createEventHandler('onPressStart'),
764
- onPressEnd: createEventHandler('onPressEnd'),
765
- });
766
- return <div ref={ref} listeners={listener} />;
767
- };
768
- ReactDOM.render(<Component />, container);
769
-
770
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
771
- ref.current.dispatchEvent(createEvent('pointerdown'));
772
- ref.current.dispatchEvent(
773
- createEvent('pointermove', coordinatesInside),
774
- );
775
- ref.current.dispatchEvent(createEvent('pointerup', coordinatesInside));
578
+ const target = ref.current;
579
+ target.getBoundingClientRect = getBoundingClientRectMock;
580
+ dispatchPointerDown(target, {pointerType});
581
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
582
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
583
jest.runAllTimers();
777
-
584
expect(events).toEqual([
585
'onPressStart',
586
'onPressChange',
@@ -786,12 +592,41 @@ describe('Event responder: Press', () => {
592
});
593
594
it('"onPress*" events are correctly called with target change', () => {
789
- let events = [];
790
- const outerRef = React.createRef();
791
- const innerRef = React.createRef();
595
+ const target = ref.current;
596
+ const outer = outerRef.current;
597
+ target.getBoundingClientRect = getBoundingClientRectMock;
598
+ dispatchPointerDown(target, {pointerType});
599
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
600
+ // TODO: this sequence may differ in the future between PointerEvent and mouse fallback when
601
+ // use 'setPointerCapture'.
602
+ if (pointerType === 'touch') {
603
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
604
+ } else {
605
+ dispatchPointerMove(outer, {pointerType, ...coordinatesOutside});
606
+ }
607
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
608
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
609
+
610
+ expect(events.filter(removePressMoveStrings)).toEqual([
611
+ 'onPressStart',
612
+ 'onPressChange',
613
+ 'onPressEnd',
614
+ 'onPressChange',
615
+ 'onPressStart',
616
+ 'onPressChange',
617
+ 'onPressEnd',
618
+ 'onPressChange',
619
+ 'onPress',
620
+ ]);
621
+ });
622
+
623
+ it('press retention offset can be configured', () => {
624
+ let localEvents = [];
625
+ const localRef = React.createRef();
626
const createEventHandler = msg => () => {
793
- events.push(msg);
627
+ localEvents.push(msg);
628
};
629
+ const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
630
631
const Component = () => {
632
const listener = usePressResponder({
@@ -800,72 +635,22 @@ describe('Event responder: Press', () => {
635
onPressMove: createEventHandler('onPressMove'),
636
onPressStart: createEventHandler('onPressStart'),
637
onPressEnd: createEventHandler('onPressEnd'),
638
+ pressRetentionOffset,
639
});
804
- return (
805
- <div ref={outerRef}>
806
- <div ref={innerRef} listeners={listener} />
807
- </div>
808
- );
640
+ return <div ref={localRef} listeners={listener} />;
641
};
642
ReactDOM.render(<Component />, container);
643
812
- innerRef.current.getBoundingClientRect = getBoundingClientRectMock;
813
- innerRef.current.dispatchEvent(createEvent('pointerdown'));
814
- outerRef.current.dispatchEvent(
815
- createEvent('pointermove', coordinatesOutside),
816
- );
817
- innerRef.current.dispatchEvent(
818
- createEvent('pointermove', coordinatesInside),
819
- );
820
- innerRef.current.dispatchEvent(
821
- createEvent('pointerup', coordinatesInside),
822
- );
823
- jest.runAllTimers();
824
-
825
- expect(events).toEqual([
826
- 'onPressStart',
827
- 'onPressChange',
828
- 'onPressEnd',
829
- 'onPressChange',
830
- 'onPressStart',
831
- 'onPressChange',
832
- 'onPressEnd',
833
- 'onPressChange',
834
- 'onPress',
835
- ]);
836
- });
837
-
838
- it('press retention offset can be configured', () => {
839
- let events = [];
840
- const ref = React.createRef();
841
- const createEventHandler = msg => () => {
842
- events.push(msg);
843
- };
844
- const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
845
-
846
- const Component = () => {
847
- const listener = usePressResponder({
848
- onPress: createEventHandler('onPress'),
849
- onPressChange: createEventHandler('onPressChange'),
850
- onPressMove: createEventHandler('onPressMove'),
851
- onPressStart: createEventHandler('onPressStart'),
852
- onPressEnd: createEventHandler('onPressEnd'),
853
- pressRetentionOffset,
854
- });
855
- return <div ref={ref} listeners={listener} />;
856
- };
857
- ReactDOM.render(<Component />, container);
858
-
859
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
860
- ref.current.dispatchEvent(createEvent('pointerdown'));
861
- ref.current.dispatchEvent(
862
- createEvent('pointermove', {
863
- clientX: rectMock.left - pressRetentionOffset.left,
864
- clientY: rectMock.top - pressRetentionOffset.top,
865
- }),
866
- );
867
- ref.current.dispatchEvent(createEvent('pointerup', coordinatesInside));
868
- expect(events).toEqual([
644
+ const target = localRef.current;
645
+ target.getBoundingClientRect = getBoundingClientRectMock;
646
+ dispatchPointerDown(target, {pointerType});
647
+ dispatchPointerMove(target, {
648
+ pointerType,
649
+ x: rectMock.left,
650
+ y: rectMock.top,
651
+ });
652
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
653
+ expect(localEvents).toEqual([
654
'onPressStart',
655
'onPressChange',
656
'onPressMove',
@@ -876,26 +661,11 @@ describe('Event responder: Press', () => {
661
});
662
663
it('responder region accounts for decrease in element dimensions', () => {
879
- let events = [];
880
- const ref = React.createRef();
881
- const createEventHandler = msg => () => {
882
- events.push(msg);
883
- };
884
-
885
- const Component = () => {
886
- const listener = usePressResponder({
887
- onPress: createEventHandler('onPress'),
888
- onPressStart: createEventHandler('onPressStart'),
889
- onPressEnd: createEventHandler('onPressEnd'),
890
- });
891
- return <div ref={ref} listeners={listener} />;
892
- };
893
- ReactDOM.render(<Component />, container);
894
-
895
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
896
- ref.current.dispatchEvent(createEvent('pointerdown'));
664
+ const target = ref.current;
665
+ target.getBoundingClientRect = getBoundingClientRectMock;
666
+ dispatchPointerDown(target, {pointerType});
667
// emulate smaller dimensions change on activation
898
- ref.current.getBoundingClientRect = () => ({
668
+ target.getBoundingClientRect = () => ({
669
width: 80,
670
height: 80,
671
top: 60,
@@ -904,36 +674,28 @@ describe('Event responder: Press', () => {
674
bottom: 490,
675
});
676
const coordinates = {
907
- clientX: rectMock.left,
908
- clientY: rectMock.top,
677
+ x: rectMock.left,
678
+ y: rectMock.top,
679
};
680
// move to an area within the pre-activation region
911
- ref.current.dispatchEvent(createEvent('pointermove', coordinates));
912
- ref.current.dispatchEvent(createEvent('pointerup', coordinates));
913
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
681
+ dispatchPointerMove(target, {pointerType, ...coordinates});
682
+ dispatchPointerUp(target, {pointerType, ...coordinates});
683
+ expect(events).toEqual([
684
+ 'onPressStart',
685
+ 'onPressChange',
686
+ 'onPressMove',
687
+ 'onPressEnd',
688
+ 'onPressChange',
689
+ 'onPress',
690
+ ]);
691
});
692
693
it('responder region accounts for increase in element dimensions', () => {
917
- let events = [];
918
- const ref = React.createRef();
919
- const createEventHandler = msg => () => {
920
- events.push(msg);
921
- };
922
-
923
- const Component = () => {
924
- const listener = usePressResponder({
925
- onPress: createEventHandler('onPress'),
926
- onPressStart: createEventHandler('onPressStart'),
927
- onPressEnd: createEventHandler('onPressEnd'),
928
- });
929
- return <div ref={ref} listeners={listener} />;
930
- };
931
- ReactDOM.render(<Component />, container);
932
-
933
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
934
- ref.current.dispatchEvent(createEvent('pointerdown'));
694
+ const target = ref.current;
695
+ target.getBoundingClientRect = getBoundingClientRectMock;
696
+ dispatchPointerDown(target, {pointerType});
697
// emulate larger dimensions change on activation
936
- ref.current.getBoundingClientRect = () => ({
698
+ target.getBoundingClientRect = () => ({
699
width: 200,
700
height: 200,
701
top: 0,
@@ -942,397 +704,12 @@ describe('Event responder: Press', () => {
704
bottom: 550,
705
});
706
const coordinates = {
945
- clientX: rectMock.left - 50,
946
- clientY: rectMock.top - 50,
707
+ x: rectMock.left - 50,
708
+ y: rectMock.top - 50,
709
};
710
// move to an area within the post-activation region
949
- ref.current.dispatchEvent(createEvent('pointermove', coordinates));
950
- ref.current.dispatchEvent(createEvent('pointerup', coordinates));
951
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
952
- });
953
- });
954
-
955
- describe('beyond bounds of hit rect', () => {
956
- /** ┌──────────────────┐
957
- * │ ┌────────────┐ │
958
- * │ │ VisualRect │ │
959
- * │ └────────────┘ │
960
- * │ HitRect │
961
- * └──────────────────┘
962
- * X <= Move to X and release
963
- */
964
-
965
- it('"onPress" is not called on release', () => {
966
- let events = [];
967
- const ref = React.createRef();
968
- const createEventHandler = msg => () => {
969
- events.push(msg);
970
- };
971
-
972
- const Component = () => {
973
- const listener = usePressResponder({
974
- onPress: createEventHandler('onPress'),
975
- onPressChange: createEventHandler('onPressChange'),
976
- onPressMove: createEventHandler('onPressMove'),
977
- onPressStart: createEventHandler('onPressStart'),
978
- onPressEnd: createEventHandler('onPressEnd'),
979
- });
980
- return <div ref={ref} listeners={listener} />;
981
- };
982
- ReactDOM.render(<Component />, container);
983
-
984
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
985
- ref.current.dispatchEvent(createEvent('pointerdown'));
986
- ref.current.dispatchEvent(
987
- createEvent('pointermove', coordinatesInside),
988
- );
989
- container.dispatchEvent(createEvent('pointermove', coordinatesOutside));
990
- container.dispatchEvent(createEvent('pointerup', coordinatesOutside));
991
- jest.runAllTimers();
992
-
993
- expect(events).toEqual([
994
- 'onPressStart',
995
- 'onPressChange',
996
- 'onPressMove',
997
- 'onPressEnd',
998
- 'onPressChange',
999
- ]);
1000
- });
1001
- });
1002
-
1003
- it('"onPress" is not called on release with mouse', () => {
1004
- let events = [];
1005
- const ref = React.createRef();
1006
- const createEventHandler = msg => () => {
1007
- events.push(msg);
1008
- };
1009
-
1010
- const Component = () => {
1011
- const listener = usePressResponder({
1012
- onPress: createEventHandler('onPress'),
1013
- onPressChange: createEventHandler('onPressChange'),
1014
- onPressMove: createEventHandler('onPressMove'),
1015
- onPressStart: createEventHandler('onPressStart'),
1016
- onPressEnd: createEventHandler('onPressEnd'),
1017
- });
1018
- return <div ref={ref} listeners={listener} />;
1019
- };
1020
- ReactDOM.render(<Component />, container);
1021
-
1022
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1023
- ref.current.dispatchEvent(
1024
- createEvent('pointerdown', {
1025
- pointerType: 'mouse',
1026
- }),
1027
- );
1028
- ref.current.dispatchEvent(
1029
- createEvent('pointermove', {
1030
- ...coordinatesInside,
1031
- pointerType: 'mouse',
1032
- }),
1033
- );
1034
- container.dispatchEvent(
1035
- createEvent('pointermove', {
1036
- ...coordinatesOutside,
1037
- pointerType: 'mouse',
1038
- }),
1039
- );
1040
- container.dispatchEvent(
1041
- createEvent('pointerup', {
1042
- ...coordinatesOutside,
1043
- pointerType: 'mouse',
1044
- }),
1045
- );
1046
- jest.runAllTimers();
1047
-
1048
- expect(events).toEqual([
1049
- 'onPressStart',
1050
- 'onPressChange',
1051
- 'onPressMove',
1052
- 'onPressEnd',
1053
- 'onPressChange',
1054
- ]);
1055
- });
1056
-
1057
- it('"onPress" is called on re-entry to hit rect for mouse', () => {
1058
- let events = [];
1059
- const ref = React.createRef();
1060
- const createEventHandler = msg => () => {
1061
- events.push(msg);
1062
- };
1063
-
1064
- const Component = () => {
1065
- const listener = usePressResponder({
1066
- onPress: createEventHandler('onPress'),
1067
- onPressChange: createEventHandler('onPressChange'),
1068
- onPressMove: createEventHandler('onPressMove'),
1069
- onPressStart: createEventHandler('onPressStart'),
1070
- onPressEnd: createEventHandler('onPressEnd'),
1071
- });
1072
- return <div ref={ref} listeners={listener} />;
1073
- };
1074
- ReactDOM.render(<Component />, container);
1075
-
1076
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1077
- ref.current.dispatchEvent(
1078
- createEvent('pointerdown', {
1079
- pointerType: 'mouse',
1080
- }),
1081
- );
1082
- ref.current.dispatchEvent(
1083
- createEvent('pointermove', {
1084
- ...coordinatesInside,
1085
- pointerType: 'mouse',
1086
- }),
1087
- );
1088
- container.dispatchEvent(
1089
- createEvent('pointermove', {
1090
- ...coordinatesOutside,
1091
- pointerType: 'mouse',
1092
- }),
1093
- );
1094
- container.dispatchEvent(
1095
- createEvent('pointermove', {
1096
- ...coordinatesInside,
1097
- pointerType: 'mouse',
1098
- }),
1099
- );
1100
- container.dispatchEvent(
1101
- createEvent('pointerup', {
1102
- ...coordinatesInside,
1103
- pointerType: 'mouse',
1104
- }),
1105
- );
1106
- jest.runAllTimers();
1107
-
1108
- expect(events).toEqual([
1109
- 'onPressStart',
1110
- 'onPressChange',
1111
- 'onPressMove',
1112
- 'onPressEnd',
1113
- 'onPressChange',
1114
- 'onPressStart',
1115
- 'onPressChange',
1116
- 'onPressEnd',
1117
- 'onPressChange',
1118
- 'onPress',
1119
- ]);
1120
- });
1121
-
1122
- it('"onPress" is called on re-entry to hit rect for touch', () => {
1123
- let events = [];
1124
- const ref = React.createRef();
1125
- const createEventHandler = msg => () => {
1126
- events.push(msg);
1127
- };
1128
-
1129
- const Component = () => {
1130
- const listener = usePressResponder({
1131
- onPress: createEventHandler('onPress'),
1132
- onPressChange: createEventHandler('onPressChange'),
1133
- onPressMove: createEventHandler('onPressMove'),
1134
- onPressStart: createEventHandler('onPressStart'),
1135
- onPressEnd: createEventHandler('onPressEnd'),
1136
- });
1137
- return <div ref={ref} listeners={listener} />;
1138
- };
1139
- ReactDOM.render(<Component />, container);
1140
-
1141
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1142
- ref.current.dispatchEvent(
1143
- createEvent('pointerdown', {
1144
- pointerType: 'touch',
1145
- }),
1146
- );
1147
- ref.current.dispatchEvent(
1148
- createTouchEvent('touchstart', 0, {
1149
- target: ref.current,
1150
- }),
1151
- );
1152
- ref.current.dispatchEvent(
1153
- createEvent('pointermove', {
1154
- ...coordinatesInside,
1155
- pointerType: 'touch',
1156
- }),
1157
- );
1158
- ref.current.dispatchEvent(
1159
- createTouchEvent('touchmove', 0, {
1160
- ...coordinatesInside,
1161
- target: ref.current,
1162
- }),
1163
- );
1164
- container.dispatchEvent(
1165
- createEvent('pointermove', {
1166
- ...coordinatesOutside,
1167
- pointerType: 'touch',
1168
- }),
1169
- );
1170
- ref.current.dispatchEvent(
1171
- createTouchEvent('touchmove', 0, {
1172
- ...coordinatesOutside,
1173
- target: ref.current,
1174
- }),
1175
- );
1176
- container.dispatchEvent(
1177
- createEvent('pointermove', {
1178
- ...coordinatesInside,
1179
- pointerType: 'touch',
1180
- }),
1181
- );
1182
- ref.current.dispatchEvent(
1183
- createTouchEvent('touchmove', 0, {
1184
- ...coordinatesInside,
1185
- target: ref.current,
1186
- }),
1187
- );
1188
- ref.current.dispatchEvent(
1189
- createTouchEvent('touchend', 0, {
1190
- ...coordinatesInside,
1191
- target: ref.current,
1192
- }),
1193
- );
1194
- container.dispatchEvent(
1195
- createEvent('pointerup', {
1196
- ...coordinatesInside,
1197
- pointerType: 'touch',
1198
- }),
1199
- );
1200
- jest.runAllTimers();
1201
-
1202
- expect(events).toEqual([
1203
- 'onPressStart',
1204
- 'onPressChange',
1205
- 'onPressMove',
1206
- 'onPressEnd',
1207
- 'onPressChange',
1208
- 'onPressStart',
1209
- 'onPressChange',
1210
- 'onPressEnd',
1211
- 'onPressChange',
1212
- 'onPress',
1213
- ]);
1214
- });
1215
- });
1216
-
1217
- describe('press with movement (touch events fallback)', () => {
1218
- const rectMock = {
1219
- width: 100,
1220
- height: 100,
1221
- top: 50,
1222
- left: 50,
1223
- right: 150,
1224
- bottom: 150,
1225
- };
1226
- const pressRectOffset = 20;
1227
- const getBoundingClientRectMock = () => rectMock;
1228
- const coordinatesInside = {
1229
- clientX: rectMock.left - pressRectOffset,
1230
- clientY: rectMock.top - pressRectOffset,
1231
- };
1232
- const coordinatesOutside = {
1233
- clientX: rectMock.left - pressRectOffset - 1,
1234
- clientY: rectMock.top - pressRectOffset - 1,
1235
- };
1236
-
1237
- describe('within bounds of hit rect', () => {
1238
- /** ┌──────────────────┐
1239
- * │ ┌────────────┐ │
1240
- * │ │ VisualRect │ │
1241
- * │ └────────────┘ │
1242
- * │ HitRect X │ <= Move to X and release
1243
- * └──────────────────┘
1244
- */
1245
- it('"onPress*" events are called immediately', () => {
1246
- let events = [];
1247
- const ref = React.createRef();
1248
- const createEventHandler = msg => () => {
1249
- events.push(msg);
1250
- };
1251
-
1252
- const Component = () => {
1253
- const listener = usePressResponder({
1254
- onPress: createEventHandler('onPress'),
1255
- onPressChange: createEventHandler('onPressChange'),
1256
- onPressMove: createEventHandler('onPressMove'),
1257
- onPressStart: createEventHandler('onPressStart'),
1258
- onPressEnd: createEventHandler('onPressEnd'),
1259
- });
1260
- return <div ref={ref} listeners={listener} />;
1261
- };
1262
- ReactDOM.render(<Component />, container);
1263
-
1264
- document.elementFromPoint = () => ref.current;
1265
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1266
- ref.current.dispatchEvent(
1267
- createTouchEvent('touchstart', 0, {
1268
- target: ref.current,
1269
- }),
1270
- );
1271
- ref.current.dispatchEvent(
1272
- createTouchEvent('touchmove', 0, {
1273
- ...coordinatesInside,
1274
- target: ref.current,
1275
- }),
1276
- );
1277
- ref.current.dispatchEvent(
1278
- createTouchEvent('touchend', 0, {
1279
- ...coordinatesInside,
1280
- target: ref.current,
1281
- }),
1282
- );
1283
- jest.runAllTimers();
1284
-
1285
- expect(events).toEqual([
1286
- 'onPressStart',
1287
- 'onPressChange',
1288
- 'onPressMove',
1289
- 'onPressEnd',
1290
- 'onPressChange',
1291
- 'onPress',
1292
- ]);
1293
- });
1294
-
1295
- it('press retention offset can be configured', () => {
1296
- let events = [];
1297
- const ref = React.createRef();
1298
- const createEventHandler = msg => () => {
1299
- events.push(msg);
1300
- };
1301
- const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
1302
-
1303
- const Component = () => {
1304
- const listener = usePressResponder({
1305
- onPress: createEventHandler('onPress'),
1306
- onPressChange: createEventHandler('onPressChange'),
1307
- onPressMove: createEventHandler('onPressMove'),
1308
- onPressStart: createEventHandler('onPressStart'),
1309
- onPressEnd: createEventHandler('onPressEnd'),
1310
- pressRetentionOffset,
1311
- });
1312
- return <div ref={ref} listeners={listener} />;
1313
- };
1314
- ReactDOM.render(<Component />, container);
1315
-
1316
- document.elementFromPoint = () => ref.current;
1317
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1318
- ref.current.dispatchEvent(
1319
- createTouchEvent('touchstart', 0, {
1320
- target: ref.current,
1321
- }),
1322
- );
1323
- ref.current.dispatchEvent(
1324
- createTouchEvent('touchmove', 0, {
1325
- clientX: rectMock.left - pressRetentionOffset.left,
1326
- clientY: rectMock.top - pressRetentionOffset.top,
1327
- target: ref.current,
1328
- }),
1329
- );
1330
- ref.current.dispatchEvent(
1331
- createTouchEvent('touchend', 0, {
1332
- ...coordinatesInside,
1333
- target: ref.current,
1334
- }),
1335
- );
711
+ dispatchPointerMove(target, {pointerType, ...coordinates});
712
+ dispatchPointerUp(target, {pointerType, ...coordinates});
713
expect(events).toEqual([
714
'onPressStart',
715
'onPressChange',
@@ -1342,112 +719,6 @@ describe('Event responder: Press', () => {
719
'onPress',
720
]);
721
});
1345
-
1346
- it('responder region accounts for decrease in element dimensions', () => {
1347
- let events = [];
1348
- const ref = React.createRef();
1349
- const createEventHandler = msg => () => {
1350
- events.push(msg);
1351
- };
1352
-
1353
- const Component = () => {
1354
- const listener = usePressResponder({
1355
- onPress: createEventHandler('onPress'),
1356
- onPressStart: createEventHandler('onPressStart'),
1357
- onPressEnd: createEventHandler('onPressEnd'),
1358
- });
1359
- return <div ref={ref} listeners={listener} />;
1360
- };
1361
- ReactDOM.render(<Component />, container);
1362
-
1363
- document.elementFromPoint = () => ref.current;
1364
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1365
- ref.current.dispatchEvent(
1366
- createTouchEvent('touchstart', 0, {
1367
- target: ref.current,
1368
- }),
1369
- );
1370
- // emulate smaller dimensions change on activation
1371
- ref.current.getBoundingClientRect = () => ({
1372
- width: 80,
1373
- height: 80,
1374
- top: 60,
1375
- left: 60,
1376
- right: 140,
1377
- bottom: 140,
1378
- });
1379
- const coordinates = {
1380
- clientX: rectMock.left,
1381
- clientY: rectMock.top,
1382
- };
1383
- // move to an area within the pre-activation region
1384
- ref.current.dispatchEvent(
1385
- createTouchEvent('touchmove', 0, {
1386
- ...coordinates,
1387
- target: ref.current,
1388
- }),
1389
- );
1390
- ref.current.dispatchEvent(
1391
- createTouchEvent('touchend', 0, {
1392
- ...coordinates,
1393
- target: ref.current,
1394
- }),
1395
- );
1396
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
1397
- });
1398
-
1399
- it('responder region accounts for increase in element dimensions', () => {
1400
- let events = [];
1401
- const ref = React.createRef();
1402
- const createEventHandler = msg => () => {
1403
- events.push(msg);
1404
- };
1405
-
1406
- const Component = () => {
1407
- const listener = usePressResponder({
1408
- onPress: createEventHandler('onPress'),
1409
- onPressStart: createEventHandler('onPressStart'),
1410
- onPressEnd: createEventHandler('onPressEnd'),
1411
- });
1412
- return <div ref={ref} listeners={listener} />;
1413
- };
1414
- ReactDOM.render(<Component />, container);
1415
-
1416
- document.elementFromPoint = () => ref.current;
1417
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1418
- ref.current.dispatchEvent(
1419
- createTouchEvent('touchstart', 0, {
1420
- target: ref.current,
1421
- }),
1422
- );
1423
- // emulate larger dimensions change on activation
1424
- ref.current.getBoundingClientRect = () => ({
1425
- width: 200,
1426
- height: 200,
1427
- top: 0,
1428
- left: 0,
1429
- right: 200,
1430
- bottom: 200,
1431
- });
1432
- const coordinates = {
1433
- clientX: rectMock.left - 50,
1434
- clientY: rectMock.top - 50,
1435
- };
1436
- // move to an area within the post-activation region
1437
- ref.current.dispatchEvent(
1438
- createTouchEvent('touchmove', 0, {
1439
- ...coordinates,
1440
- target: ref.current,
1441
- }),
1442
- );
1443
- ref.current.dispatchEvent(
1444
- createTouchEvent('touchend', 0, {
1445
- ...coordinates,
1446
- target: ref.current,
1447
- }),
1448
- );
1449
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
1450
- });
722
});
723
724
describe('beyond bounds of hit rect', () => {
@@ -1459,117 +730,40 @@ describe('Event responder: Press', () => {
730
* └──────────────────┘
731
* X <= Move to X and release
732
*/
1462
-
733
it('"onPress" is not called on release', () => {
1464
- let events = [];
1465
- const ref = React.createRef();
1466
- const createEventHandler = msg => () => {
1467
- events.push(msg);
1468
- };
1469
-
1470
- const Component = () => {
1471
- const listener = usePressResponder({
1472
- onPress: createEventHandler('onPress'),
1473
- onPressChange: createEventHandler('onPressChange'),
1474
- onPressMove: createEventHandler('onPressMove'),
1475
- onPressStart: createEventHandler('onPressStart'),
1476
- onPressEnd: createEventHandler('onPressEnd'),
1477
- });
1478
- return <div ref={ref} listeners={listener} />;
1479
- };
1480
- ReactDOM.render(<Component />, container);
1481
-
1482
- document.elementFromPoint = () => ref.current;
1483
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1484
- ref.current.dispatchEvent(
1485
- createTouchEvent('touchstart', 0, {
1486
- target: ref.current,
1487
- }),
1488
- );
1489
- ref.current.dispatchEvent(
1490
- createTouchEvent('touchmove', 0, {
1491
- ...coordinatesInside,
1492
- target: ref.current,
1493
- }),
1494
- );
1495
- document.elementFromPoint = () => container;
1496
- container.dispatchEvent(
1497
- createTouchEvent('touchmove', 0, {
1498
- ...coordinatesOutside,
1499
- target: container,
1500
- }),
1501
- );
1502
- container.dispatchEvent(
1503
- createTouchEvent('touchend', 0, {
1504
- ...coordinatesOutside,
1505
- target: container,
1506
- }),
1507
- );
1508
- jest.runAllTimers();
1509
-
1510
- expect(events).toEqual([
1511
- 'onPressStart',
1512
- 'onPressChange',
1513
- 'onPressMove',
1514
- 'onPressEnd',
1515
- 'onPressChange',
1516
- ]);
1517
- });
1518
- });
1519
-
1520
- it('"onPress" is called on re-entry to hit rect for touch', () => {
1521
- let events = [];
1522
- const ref = React.createRef();
1523
- const createEventHandler = msg => () => {
1524
- events.push(msg);
1525
- };
1526
-
1527
- const Component = () => {
1528
- const listener = usePressResponder({
1529
- onPress: createEventHandler('onPress'),
1530
- onPressChange: createEventHandler('onPressChange'),
1531
- onPressMove: createEventHandler('onPressMove'),
1532
- onPressStart: createEventHandler('onPressStart'),
1533
- onPressEnd: createEventHandler('onPressEnd'),
1534
- });
1535
- return <div ref={ref} listeners={listener} />;
1536
- };
1537
- ReactDOM.render(<Component />, container);
1538
-
1539
- document.elementFromPoint = () => ref.current;
1540
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
1541
- ref.current.dispatchEvent(
1542
- createTouchEvent('touchstart', 0, {
1543
- target: ref.current,
1544
- }),
1545
- );
1546
- ref.current.dispatchEvent(
1547
- createTouchEvent('touchmove', 0, {
1548
- ...coordinatesInside,
1549
- target: ref.current,
1550
- }),
1551
- );
1552
- document.elementFromPoint = () => container;
1553
- container.dispatchEvent(
1554
- createTouchEvent('touchmove', 0, {
1555
- ...coordinatesOutside,
1556
- target: container,
1557
- }),
1558
- );
1559
- ref.current.dispatchEvent(
1560
- createTouchEvent('touchmove', 0, {
1561
- ...coordinatesInside,
1562
- target: ref.current,
1563
- }),
1564
- );
1565
- document.elementFromPoint = () => ref.current;
1566
- ref.current.dispatchEvent(
1567
- createTouchEvent('touchend', 0, {
1568
- ...coordinatesInside,
1569
- target: ref.current,
1570
- }),
1571
- );
1572
- jest.runAllTimers();
734
+ const target = ref.current;
735
+ target.getBoundingClientRect = getBoundingClientRectMock;
736
+ dispatchPointerDown(target, {pointerType});
737
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
738
+ if (pointerType === 'mouse') {
739
+ // TODO: use setPointerCapture so this is only true for fallback mouse events.
740
+ dispatchPointerMove(container, {pointerType, ...coordinatesOutside});
741
+ } else {
742
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
743
+ }
744
+ dispatchPointerUp(container, {pointerType, ...coordinatesOutside});
745
+ expect(events.filter(removePressMoveStrings)).toEqual([
746
+ 'onPressStart',
747
+ 'onPressChange',
748
+ 'onPressEnd',
749
+ 'onPressChange',
750
+ ]);
751
+ });
752
+ });
753
+
754
+ it('"onPress" is called on re-entry to hit rect', () => {
755
+ const target = ref.current;
756
+ target.getBoundingClientRect = getBoundingClientRectMock;
757
+ dispatchPointerDown(target, {pointerType});
758
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
759
+ if (pointerType === 'mouse') {
760
+ // TODO: use setPointerCapture so this is only true for fallback mouse events.
761
+ dispatchPointerMove(container, {pointerType, ...coordinatesOutside});
762
+ } else {
763
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
764
+ }
765
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
766
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
767
768
expect(events).toEqual([
769
'onPressStart',
@@ -1587,71 +781,71 @@ describe('Event responder: Press', () => {
781
});
782
783
describe('nested responders', () => {
1590
- it('dispatch events in the correct order', () => {
1591
- const events = [];
1592
- const ref = React.createRef();
1593
- const createEventHandler = msg => () => {
1594
- events.push(msg);
1595
- };
784
+ if (hasPointerEvents) {
785
+ it('dispatch events in the correct order', () => {
786
+ const events = [];
787
+ const ref = React.createRef();
788
+ const createEventHandler = msg => () => {
789
+ events.push(msg);
790
+ };
791
1597
- const Inner = () => {
1598
- const listener = usePressResponder({
1599
- onPress: createEventHandler('inner: onPress'),
1600
- onPressChange: createEventHandler('inner: onPressChange'),
1601
- onPressMove: createEventHandler('inner: onPressMove'),
1602
- onPressStart: createEventHandler('inner: onPressStart'),
1603
- onPressEnd: createEventHandler('inner: onPressEnd'),
1604
- stopPropagation: false,
1605
- });
1606
- return (
1607
- <div
1608
- ref={ref}
1609
- listeners={listener}
1610
- onPointerDown={createEventHandler('pointerdown')}
1611
- onPointerUp={createEventHandler('pointerup')}
1612
- onKeyDown={createEventHandler('keydown')}
1613
- onKeyUp={createEventHandler('keyup')}
1614
- />
1615
- );
1616
- };
792
+ const Inner = () => {
793
+ const listener = usePressResponder({
794
+ onPress: createEventHandler('inner: onPress'),
795
+ onPressChange: createEventHandler('inner: onPressChange'),
796
+ onPressMove: createEventHandler('inner: onPressMove'),
797
+ onPressStart: createEventHandler('inner: onPressStart'),
798
+ onPressEnd: createEventHandler('inner: onPressEnd'),
799
+ stopPropagation: false,
800
+ });
801
+ return (
802
+ <div
803
+ ref={ref}
804
+ listeners={listener}
805
+ onPointerDown={createEventHandler('pointerdown')}
806
+ onPointerUp={createEventHandler('pointerup')}
807
+ onKeyDown={createEventHandler('keydown')}
808
+ onKeyUp={createEventHandler('keyup')}
809
+ />
810
+ );
811
+ };
812
1618
- const Outer = () => {
1619
- const listener = usePressResponder({
1620
- onPress: createEventHandler('outer: onPress'),
1621
- onPressChange: createEventHandler('outer: onPressChange'),
1622
- onPressMove: createEventHandler('outer: onPressMove'),
1623
- onPressStart: createEventHandler('outer: onPressStart'),
1624
- onPressEnd: createEventHandler('outer: onPressEnd'),
1625
- });
1626
- return (
1627
- <div listeners={listener}>
1628
- <Inner />
1629
- </div>
1630
- );
1631
- };
1632
- ReactDOM.render(<Outer />, container);
813
+ const Outer = () => {
814
+ const listener = usePressResponder({
815
+ onPress: createEventHandler('outer: onPress'),
816
+ onPressChange: createEventHandler('outer: onPressChange'),
817
+ onPressMove: createEventHandler('outer: onPressMove'),
818
+ onPressStart: createEventHandler('outer: onPressStart'),
819
+ onPressEnd: createEventHandler('outer: onPressEnd'),
820
+ });
821
+ return (
822
+ <div listeners={listener}>
823
+ <Inner />
824
+ </div>
825
+ );
826
+ };
827
+ ReactDOM.render(<Outer />, container);
828
1634
- ref.current.getBoundingClientRect = () => ({
1635
- top: 0,
1636
- left: 0,
1637
- bottom: 100,
1638
- right: 100,
829
+ const target = ref.current;
830
+ target.getBoundingClientRect = () => ({
831
+ top: 0,
832
+ left: 0,
833
+ bottom: 100,
834
+ right: 100,
835
+ });
836
+ dispatchPointerDown(target);
837
+ dispatchPointerUp(target);
838
+ expect(events).toEqual([
839
+ 'inner: onPressStart',
840
+ 'inner: onPressChange',
841
+ 'pointerdown',
842
+ 'inner: onPressEnd',
843
+ 'inner: onPressChange',
844
+ 'inner: onPress',
845
+ 'pointerup',
846
+ ]);
847
});
1640
-
1641
- ref.current.dispatchEvent(createEvent('pointerdown'));
1642
- ref.current.dispatchEvent(
1643
- createEvent('pointerup', {clientX: 10, clientY: 10}),
1644
- );
1645
- expect(events).toEqual([
1646
- 'inner: onPressStart',
1647
- 'inner: onPressChange',
1648
- 'pointerdown',
1649
- 'inner: onPressEnd',
1650
- 'inner: onPressChange',
1651
- 'inner: onPress',
1652
- 'pointerup',
1653
- ]);
1654
- });
848
+ }
849
850
describe('correctly not propagate', () => {
851
it('for onPress', () => {
@@ -1677,17 +871,15 @@ describe('Event responder: Press', () => {
871
};
872
ReactDOM.render(<Outer />, container);
873
1680
- ref.current.getBoundingClientRect = () => ({
874
+ const target = ref.current;
875
+ target.getBoundingClientRect = () => ({
876
top: 0,
877
left: 0,
878
bottom: 100,
879
right: 100,
880
});
1686
-
1687
- ref.current.dispatchEvent(createEvent('pointerdown'));
1688
- ref.current.dispatchEvent(
1689
- createEvent('pointerup', {clientX: 10, clientY: 10}),
1690
- );
881
+ dispatchPointerDown(target);
882
+ dispatchPointerUp(target);
883
expect(fn).toHaveBeenCalledTimes(1);
884
});
885
@@ -1717,10 +909,11 @@ describe('Event responder: Press', () => {
909
};
910
ReactDOM.render(<Outer />, container);
911
1720
- ref.current.dispatchEvent(createEvent('pointerdown'));
912
+ const target = ref.current;
913
+ dispatchPointerDown(target);
914
expect(fn).toHaveBeenCalledTimes(1);
915
expect(fn2).toHaveBeenCalledTimes(0);
1723
- ref.current.dispatchEvent(createEvent('pointerup'));
916
+ dispatchPointerUp(target);
917
expect(fn).toHaveBeenCalledTimes(1);
918
expect(fn2).toHaveBeenCalledTimes(1);
919
});
@@ -1748,16 +941,17 @@ describe('Event responder: Press', () => {
941
};
942
ReactDOM.render(<Outer />, container);
943
1751
- ref.current.dispatchEvent(createEvent('pointerdown'));
944
+ const target = ref.current;
945
+ dispatchPointerDown(target);
946
expect(fn).toHaveBeenCalledTimes(1);
1753
- ref.current.dispatchEvent(createEvent('pointerup'));
947
+ dispatchPointerUp(target);
948
expect(fn).toHaveBeenCalledTimes(2);
949
});
950
});
951
});
952
953
describe('link components', () => {
1760
- it('prevents native behaviour for pointer events by default', () => {
954
+ it('prevents native behavior by default', () => {
955
const onPress = jest.fn();
956
const preventDefault = jest.fn();
957
const ref = React.createRef();
@@ -1770,14 +964,9 @@ describe('Event responder: Press', () => {
964
};
965
ReactDOM.render(<Component />, container);
966
1773
- ref.current.dispatchEvent(createEvent('pointerdown'));
1774
- ref.current.dispatchEvent(
1775
- createEvent('pointerup', {
1776
- clientX: 0,
1777
- clientY: 0,
1778
- }),
1779
- );
1780
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
967
+ const target = ref.current;
968
+ dispatchPointerDown(target);
969
+ dispatchPointerUp(target, {preventDefault});
970
expect(preventDefault).toBeCalled();
971
expect(onPress).toHaveBeenCalledWith(
972
expect.objectContaining({defaultPrevented: true}),
@@ -1797,9 +986,10 @@ describe('Event responder: Press', () => {
986
};
987
ReactDOM.render(<Component />, container);
988
1800
- ref.current.dispatchEvent(createEvent('keydown', {key: 'Enter'}));
1801
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
1802
- ref.current.dispatchEvent(createEvent('keyup', {key: 'Enter'}));
989
+ const target = ref.current;
990
+ target.dispatchEvent(keydown({key: 'Enter'}));
991
+ target.dispatchEvent(click({preventDefault}));
992
+ target.dispatchEvent(keyup({key: 'Enter'}));
993
expect(preventDefault).toBeCalled();
994
expect(onPress).toHaveBeenCalledWith(
995
expect.objectContaining({defaultPrevented: true}),
@@ -1823,14 +1013,9 @@ describe('Event responder: Press', () => {
1013
};
1014
ReactDOM.render(<Component />, container);
1015
1826
- buttonRef.current.dispatchEvent(createEvent('pointerdown'));
1827
- buttonRef.current.dispatchEvent(
1828
- createEvent('pointerup', {
1829
- clientX: 0,
1830
- clientY: 0,
1831
- }),
1832
- );
1833
- buttonRef.current.dispatchEvent(createEvent('click', {preventDefault}));
1016
+ const target = buttonRef.current;
1017
+ dispatchPointerDown(target);
1018
+ dispatchPointerUp(target, {preventDefault});
1019
expect(preventDefault).toBeCalled();
1020
});
1021
@@ -1851,14 +1036,9 @@ describe('Event responder: Press', () => {
1036
};
1037
ReactDOM.render(<Component />, container);
1038
1854
- ref.current.dispatchEvent(createEvent('pointerdown'));
1855
- ref.current.dispatchEvent(
1856
- createEvent('pointerup', {
1857
- clientX: 0,
1858
- clientY: 0,
1859
- }),
1860
- );
1861
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
1039
+ const target = ref.current;
1040
+ dispatchPointerDown(target);
1041
+ dispatchPointerUp(target, {preventDefault});
1042
expect(preventDefault).toBeCalled();
1043
expect(onPress).toHaveBeenCalledWith(
1044
expect.objectContaining({defaultPrevented: true}),
@@ -1879,19 +1059,9 @@ describe('Event responder: Press', () => {
1059
ReactDOM.render(<Component />, container);
1060
1061
['metaKey', 'ctrlKey', 'shiftKey'].forEach(modifierKey => {
1882
- ref.current.dispatchEvent(
1883
- createEvent('pointerdown', {[modifierKey]: true}),
1884
- );
1885
- ref.current.dispatchEvent(
1886
- createEvent('pointerup', {
1887
- [modifierKey]: true,
1888
- clientX: 0,
1889
- clientY: 0,
1890
- }),
1891
- );
1892
- ref.current.dispatchEvent(
1893
- createEvent('click', {[modifierKey]: true, preventDefault}),
1894
- );
1062
+ const target = ref.current;
1063
+ dispatchPointerDown(target, {[modifierKey]: true});
1064
+ dispatchPointerUp(target, {[modifierKey]: true, preventDefault});
1065
expect(preventDefault).not.toBeCalled();
1066
expect(onPress).toHaveBeenCalledWith(
1067
expect.objectContaining({defaultPrevented: false}),
@@ -1913,14 +1083,9 @@ describe('Event responder: Press', () => {
1083
};
1084
ReactDOM.render(<Component />, container);
1085
1916
- ref.current.dispatchEvent(createEvent('pointerdown'));
1917
- ref.current.dispatchEvent(
1918
- createEvent('pointerup', {
1919
- clientX: 0,
1920
- clientY: 0,
1921
- }),
1922
- );
1923
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
1086
+ const target = ref.current;
1087
+ dispatchPointerDown(target);
1088
+ dispatchPointerUp(target, {preventDefault});
1089
expect(preventDefault).not.toBeCalled();
1090
expect(onPress).toHaveBeenCalledWith(
1091
expect.objectContaining({defaultPrevented: false}),
@@ -1941,9 +1106,10 @@ describe('Event responder: Press', () => {
1106
};
1107
ReactDOM.render(<Component />, container);
1108
1944
- ref.current.dispatchEvent(createEvent('keydown', {key: 'Enter'}));
1945
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
1946
- ref.current.dispatchEvent(createEvent('keyup', {key: 'Enter'}));
1109
+ const target = ref.current;
1110
+ target.dispatchEvent(keydown({key: 'Enter'}));
1111
+ target.dispatchEvent(click({preventDefault}));
1112
+ target.dispatchEvent(keyup({key: 'Enter'}));
1113
expect(preventDefault).not.toBeCalled();
1114
expect(onPress).toHaveBeenCalledWith(
1115
expect.objectContaining({defaultPrevented: false}),
@@ -1952,7 +1118,7 @@ describe('Event responder: Press', () => {
1118
});
1119
1120
describe('responder cancellation', () => {
1955
- it('ends on "pointercancel", "touchcancel", "scroll", and "dragstart"', () => {
1121
+ it.each(pointerTypesTable)('ends on pointer cancel', pointerType => {
1122
const onPressEnd = jest.fn();
1123
const ref = React.createRef();
1124
@@ -1964,64 +1130,14 @@ describe('Event responder: Press', () => {
1130
};
1131
ReactDOM.render(<Component />, container);
1132
1967
- // Should cancel for non-mouse events
1968
- ref.current.dispatchEvent(
1969
- createEvent('pointerdown', {
1970
- pointerType: 'touch',
1971
- }),
1972
- );
1973
- ref.current.dispatchEvent(createEvent('scroll'));
1974
- expect(onPressEnd).toHaveBeenCalledTimes(1);
1975
-
1976
- onPressEnd.mockReset();
1977
-
1978
- // Should not cancel for mouse events
1979
- ref.current.dispatchEvent(
1980
- createEvent('pointerdown', {
1981
- pointerType: 'mouse',
1982
- }),
1983
- );
1984
- ref.current.dispatchEvent(createEvent('scroll'));
1985
- expect(onPressEnd).toHaveBeenCalledTimes(0);
1986
-
1987
- // When pointer events are supported
1988
- ref.current.dispatchEvent(
1989
- createEvent('pointerdown', {
1990
- pointerType: 'mouse',
1991
- }),
1992
- );
1993
- ref.current.dispatchEvent(
1994
- createEvent('pointercancel', {
1995
- pointerType: 'mouse',
1996
- }),
1997
- );
1998
- expect(onPressEnd).toHaveBeenCalledTimes(1);
1999
-
2000
- onPressEnd.mockReset();
2001
-
2002
- // Touch fallback
2003
- ref.current.dispatchEvent(
2004
- createTouchEvent('touchstart', 0, {
2005
- target: ref.current,
2006
- }),
2007
- );
2008
- ref.current.dispatchEvent(
2009
- createTouchEvent('touchcancel', 0, {
2010
- target: ref.current,
2011
- }),
2012
- );
2013
- expect(onPressEnd).toHaveBeenCalledTimes(1);
2014
-
2015
- onPressEnd.mockReset();
2016
-
2017
- // Mouse fallback
2018
- ref.current.dispatchEvent(createEvent('mousedown'));
2019
- ref.current.dispatchEvent(createEvent('dragstart'));
1133
+ const target = ref.current;
1134
+ dispatchPointerDown(target, {pointerType});
1135
+ dispatchPointerCancel(target, {pointerType});
1136
expect(onPressEnd).toHaveBeenCalledTimes(1);
1137
});
1138
});
1139
2024
- it('does end on "scroll" to document', () => {
1140
+ it('does end on "scroll" to document (not mouse)', () => {
1141
const onPressEnd = jest.fn();
1142
const ref = React.createRef();
1143
@@ -2033,12 +1149,13 @@ describe('Event responder: Press', () => {
1149
};
1150
ReactDOM.render(<Component />, container);
1151
2036
- ref.current.dispatchEvent(createEvent('pointerdown'));
2037
- document.dispatchEvent(createEvent('scroll'));
1152
+ const target = ref.current;
1153
+ dispatchPointerDown(target, {pointerType: 'touch'});
1154
+ document.dispatchEvent(scroll());
1155
expect(onPressEnd).toHaveBeenCalledTimes(1);
1156
});
1157
2041
- it('does end on "scroll" to a parent container', () => {
1158
+ it('does end on "scroll" to a parent container (not mouse)', () => {
1159
const onPressEnd = jest.fn();
1160
const ref = React.createRef();
1161
const containerRef = React.createRef();
@@ -2055,8 +1172,8 @@ describe('Event responder: Press', () => {
1172
};
1173
ReactDOM.render(<Component />, container);
1174
2058
- ref.current.dispatchEvent(createEvent('pointerdown'));
2059
- containerRef.current.dispatchEvent(createEvent('scroll'));
1175
+ dispatchPointerDown(ref.current, {pointerType: 'touch'});
1176
+ containerRef.current.dispatchEvent(scroll());
1177
expect(onPressEnd).toHaveBeenCalledTimes(1);
1178
});
1179
@@ -2078,8 +1195,8 @@ describe('Event responder: Press', () => {
1195
};
1196
ReactDOM.render(<Component />, container);
1197
2081
- ref.current.dispatchEvent(createEvent('pointerdown'));
2082
- outsideRef.current.dispatchEvent(createEvent('scroll'));
1198
+ dispatchPointerDown(ref.current);
1199
+ outsideRef.current.dispatchEvent(scroll());
1200
expect(onPressEnd).not.toBeCalled();
1201
});
1202
@@ -2095,10 +1212,11 @@ describe('Event responder: Press', () => {
1212
};
1213
ReactDOM.render(<Component />, container);
1214
2098
- ref.current.dispatchEvent(createEvent('pointerdown'));
2099
- ref.current.dispatchEvent(createEvent('pointermove'));
2100
- ref.current.dispatchEvent(createEvent('pointerup'));
2101
- ref.current.dispatchEvent(createEvent('pointerdown'));
1215
+ const target = ref.current;
1216
+ dispatchPointerDown(target);
1217
+ dispatchPointerMove(target);
1218
+ dispatchPointerUp(target);
1219
+ dispatchPointerDown(target);
1220
});
1221
1222
it('should correctly pass through event properties', () => {
@@ -2133,57 +1251,49 @@ describe('Event responder: Press', () => {
1251
};
1252
ReactDOM.render(<Component />, container);
1253
2136
- ref.current.getBoundingClientRect = () => ({
1254
+ const target = ref.current;
1255
+ target.getBoundingClientRect = () => ({
1256
top: 10,
1257
left: 10,
1258
bottom: 110,
1259
right: 110,
1260
});
2142
-
2143
- ref.current.dispatchEvent(
2144
- createEvent('pointerdown', {
2145
- pointerType: 'mouse',
2146
- pageX: 15,
2147
- pageY: 16,
2148
- screenX: 20,
2149
- screenY: 21,
2150
- clientX: 30,
2151
- clientY: 31,
2152
- }),
2153
- );
2154
- ref.current.dispatchEvent(
2155
- createEvent('pointermove', {
2156
- pointerType: 'mouse',
2157
- pageX: 16,
2158
- pageY: 17,
2159
- screenX: 21,
2160
- screenY: 22,
2161
- clientX: 31,
2162
- clientY: 32,
2163
- }),
2164
- );
2165
- ref.current.dispatchEvent(
2166
- createEvent('pointerup', {
2167
- pointerType: 'mouse',
2168
- pageX: 17,
2169
- pageY: 18,
2170
- screenX: 22,
2171
- screenY: 23,
2172
- clientX: 32,
2173
- clientY: 33,
2174
- }),
2175
- );
2176
- ref.current.dispatchEvent(
2177
- createEvent('pointerdown', {
2178
- pointerType: 'mouse',
2179
- pageX: 18,
2180
- pageY: 19,
2181
- screenX: 23,
2182
- screenY: 24,
2183
- clientX: 33,
2184
- clientY: 34,
2185
- }),
2186
- );
1261
+ dispatchPointerDown(target, {
1262
+ pointerType: 'mouse',
1263
+ pageX: 15,
1264
+ pageY: 16,
1265
+ screenX: 20,
1266
+ screenY: 21,
1267
+ clientX: 30,
1268
+ clientY: 31,
1269
+ });
1270
+ dispatchPointerMove(target, {
1271
+ pointerType: 'mouse',
1272
+ pageX: 16,
1273
+ pageY: 17,
1274
+ screenX: 21,
1275
+ screenY: 22,
1276
+ clientX: 31,
1277
+ clientY: 32,
1278
+ });
1279
+ dispatchPointerUp(target, {
1280
+ pointerType: 'mouse',
1281
+ pageX: 17,
1282
+ pageY: 18,
1283
+ screenX: 22,
1284
+ screenY: 23,
1285
+ clientX: 32,
1286
+ clientY: 33,
1287
+ });
1288
+ dispatchPointerDown(target, {
1289
+ pointerType: 'mouse',
1290
+ pageX: 18,
1291
+ pageY: 19,
1292
+ screenX: 23,
1293
+ screenY: 24,
1294
+ clientX: 33,
1295
+ clientY: 34,
1296
+ });
1297
expect(typeof timeStamps[0] === 'number').toBe(true);
1298
expect(eventLog).toEqual([
1299
{
@@ -2249,175 +1359,85 @@ describe('Event responder: Press', () => {
1359
]);
1360
});
1361
2252
- function dispatchEventWithTimeStamp(elem, name, timeStamp) {
2253
- const event = createEvent(name, {
2254
- clientX: 0,
2255
- clientY: 0,
2256
- });
2257
- Object.defineProperty(event, 'timeStamp', {
2258
- value: timeStamp,
2259
- });
2260
- elem.dispatchEvent(event);
2261
- }
2262
-
2263
- it('should properly only flush sync once when the event systems are mixed', () => {
2264
- const ref = React.createRef();
2265
- let renderCounts = 0;
2266
-
2267
- function MyComponent() {
2268
- const [, updateCounter] = React.useState(0);
2269
- renderCounts++;
2270
-
2271
- function handlePress() {
2272
- updateCounter(count => count + 1);
2273
- }
2274
-
2275
- const listener = usePressResponder({
2276
- onPress: handlePress,
2277
- });
2278
-
2279
- return (
2280
- <div>
2281
- <button
2282
- ref={ref}
2283
- listeners={listener}
2284
- onClick={() => {
2285
- updateCounter(count => count + 1);
2286
- }}>
2287
- Press me
2288
- </button>
2289
- </div>
2290
- );
2291
- }
2292
-
2293
- const newContainer = document.createElement('div');
2294
- const root = ReactDOM.unstable_createRoot(newContainer);
2295
- document.body.appendChild(newContainer);
2296
- root.render(<MyComponent />);
2297
- Scheduler.unstable_flushAll();
2298
-
2299
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
2300
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
2301
- dispatchEventWithTimeStamp(ref.current, 'click', 100);
2302
-
2303
- if (__DEV__) {
2304
- expect(renderCounts).toBe(2);
2305
- } else {
2306
- expect(renderCounts).toBe(1);
2307
- }
2308
- Scheduler.unstable_flushAll();
2309
- if (__DEV__) {
2310
- expect(renderCounts).toBe(4);
2311
- } else {
2312
- expect(renderCounts).toBe(2);
2313
- }
2314
-
2315
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
2316
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
2317
- // Ensure the timeStamp logic works
2318
- dispatchEventWithTimeStamp(ref.current, 'click', 101);
2319
-
2320
- if (__DEV__) {
2321
- expect(renderCounts).toBe(6);
2322
- } else {
2323
- expect(renderCounts).toBe(3);
2324
- }
1362
+ if (hasPointerEvents) {
1363
+ it('should properly only flush sync once when the event systems are mixed', () => {
1364
+ const ref = React.createRef();
1365
+ let renderCounts = 0;
1366
2326
- Scheduler.unstable_flushAll();
2327
- document.body.removeChild(newContainer);
2328
- });
1367
+ function MyComponent() {
1368
+ const [, updateCounter] = React.useState(0);
1369
+ renderCounts++;
1370
2330
- it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
2331
- const ref = React.createRef();
2332
- let renderCounts = 0;
1371
+ function handlePress() {
1372
+ updateCounter(count => count + 1);
1373
+ }
1374
2334
- function MyComponent() {
2335
- const [, updateCounter] = React.useState(0);
2336
- renderCounts++;
1375
+ const listener = usePressResponder({
1376
+ onPress: handlePress,
1377
+ });
1378
2338
- function handlePress() {
2339
- updateCounter(count => count + 1);
1379
+ return (
1380
+ <div>
1381
+ <button
1382
+ ref={ref}
1383
+ listeners={listener}
1384
+ onClick={() => {
1385
+ updateCounter(count => count + 1);
1386
+ }}>
1387
+ Press me
1388
+ </button>
1389
+ </div>
1390
+ );
1391
}
1392
2342
- const listener = usePressResponder({
2343
- onPress: handlePress,
2344
- });
2345
-
2346
- return (
2347
- <div>
2348
- <button
2349
- ref={ref}
2350
- listeners={listener}
2351
- onClick={() => {
2352
- // This should flush synchronously
2353
- ReactDOM.unstable_flushDiscreteUpdates();
2354
- updateCounter(count => count + 1);
2355
- }}>
2356
- Press me
2357
- </button>
2358
- </div>
2359
- );
2360
- }
2361
-
2362
- const newContainer = document.createElement('div');
2363
- const root = ReactDOM.unstable_createRoot(newContainer);
2364
- document.body.appendChild(newContainer);
2365
- root.render(<MyComponent />);
2366
- Scheduler.unstable_flushAll();
2367
-
2368
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
2369
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
2370
- dispatchEventWithTimeStamp(ref.current, 'click', 100);
2371
-
2372
- if (__DEV__) {
2373
- expect(renderCounts).toBe(4);
2374
- } else {
2375
- expect(renderCounts).toBe(2);
2376
- }
2377
- Scheduler.unstable_flushAll();
2378
- if (__DEV__) {
2379
- expect(renderCounts).toBe(6);
2380
- } else {
2381
- expect(renderCounts).toBe(3);
2382
- }
1393
+ const newContainer = document.createElement('div');
1394
+ const root = ReactDOM.unstable_createRoot(newContainer);
1395
+ document.body.appendChild(newContainer);
1396
+ root.render(<MyComponent />);
1397
+ Scheduler.unstable_flushAll();
1398
2384
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
2385
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
2386
- // Ensure the timeStamp logic works
2387
- dispatchEventWithTimeStamp(ref.current, 'click', 101);
1399
+ const target = ref.current;
1400
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
1401
+ target.dispatchEvent(pointerup({timeStamp: 100}));
1402
+ target.dispatchEvent(click({timeStamp: 100}));
1403
2389
- if (__DEV__) {
2390
- expect(renderCounts).toBe(8);
2391
- } else {
2392
- expect(renderCounts).toBe(4);
2393
- }
1404
+ if (__DEV__) {
1405
+ expect(renderCounts).toBe(2);
1406
+ } else {
1407
+ expect(renderCounts).toBe(1);
1408
+ }
1409
+ Scheduler.unstable_flushAll();
1410
+ if (__DEV__) {
1411
+ expect(renderCounts).toBe(4);
1412
+ } else {
1413
+ expect(renderCounts).toBe(2);
1414
+ }
1415
2395
- Scheduler.unstable_flushAll();
2396
- document.body.removeChild(newContainer);
2397
- });
1416
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
1417
+ target.dispatchEvent(pointerup({timeStamp: 100}));
1418
+ // Ensure the timeStamp logic works
1419
+ target.dispatchEvent(click({timeStamp: 101}));
1420
2399
- it(
2400
- 'should only flush before outermost discrete event handler when mixing ' +
2401
- 'event systems',
2402
- async () => {
2403
- const {useState} = React;
1421
+ if (__DEV__) {
1422
+ expect(renderCounts).toBe(6);
1423
+ } else {
1424
+ expect(renderCounts).toBe(3);
1425
+ }
1426
2405
- const button = React.createRef();
1427
+ Scheduler.unstable_flushAll();
1428
+ document.body.removeChild(newContainer);
1429
+ });
1430
2407
- const ops = [];
1431
+ it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
1432
+ const ref = React.createRef();
1433
+ let renderCounts = 0;
1434
1435
function MyComponent() {
2410
- const [pressesCount, updatePressesCount] = useState(0);
2411
- const [clicksCount, updateClicksCount] = useState(0);
1436
+ const [, updateCounter] = React.useState(0);
1437
+ renderCounts++;
1438
1439
function handlePress() {
2414
- // This dispatches a synchronous, discrete event in the legacy event
2415
- // system. However, because it's nested inside the new event system,
2416
- // its updates should not flush until the end of the outer handler.
2417
- button.current.click();
2418
- // Text context should not have changed
2419
- ops.push(newContainer.textContent);
2420
- updatePressesCount(pressesCount + 1);
1440
+ updateCounter(count => count + 1);
1441
}
1442
1443
const listener = usePressResponder({
@@ -2427,76 +1447,131 @@ describe('Event responder: Press', () => {
1447
return (
1448
<div>
1449
<button
1450
+ ref={ref}
1451
listeners={listener}
2431
- ref={button}
2432
- onClick={() => updateClicksCount(clicksCount + 1)}>
2433
- Presses: {pressesCount}, Clicks: {clicksCount}
1452
+ onClick={() => {
1453
+ // This should flush synchronously
1454
+ ReactDOM.unstable_flushDiscreteUpdates();
1455
+ updateCounter(count => count + 1);
1456
+ }}>
1457
+ Press me
1458
</button>
1459
</div>
1460
);
1461
}
1462
1463
const newContainer = document.createElement('div');
2440
- document.body.appendChild(newContainer);
1464
const root = ReactDOM.unstable_createRoot(newContainer);
2442
-
1465
+ document.body.appendChild(newContainer);
1466
root.render(<MyComponent />);
1467
Scheduler.unstable_flushAll();
2445
- expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
1468
2447
- dispatchEventWithTimeStamp(button.current, 'pointerdown', 100);
2448
- dispatchEventWithTimeStamp(button.current, 'pointerup', 100);
2449
- dispatchEventWithTimeStamp(button.current, 'click', 100);
1469
+ const target = ref.current;
1470
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
1471
+ target.dispatchEvent(pointerup({timeStamp: 100}));
1472
+ target.dispatchEvent(click({timeStamp: 100}));
1473
+
1474
+ if (__DEV__) {
1475
+ expect(renderCounts).toBe(4);
1476
+ } else {
1477
+ expect(renderCounts).toBe(2);
1478
+ }
1479
Scheduler.unstable_flushAll();
2451
- expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
1480
+ if (__DEV__) {
1481
+ expect(renderCounts).toBe(6);
1482
+ } else {
1483
+ expect(renderCounts).toBe(3);
1484
+ }
1485
2453
- expect(ops).toEqual(['Presses: 0, Clicks: 0']);
2454
- },
2455
- );
1486
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
1487
+ target.dispatchEvent(pointerup({timeStamp: 100}));
1488
+ // Ensure the timeStamp logic works
1489
+ target.dispatchEvent(click({timeStamp: 101}));
1490
2457
- it('should work correctly with stopPropagation set to true', () => {
2458
- const ref = React.createRef();
2459
- const pointerDownEvent = jest.fn();
1491
+ if (__DEV__) {
1492
+ expect(renderCounts).toBe(8);
1493
+ } else {
1494
+ expect(renderCounts).toBe(4);
1495
+ }
1496
2461
- const Component = () => {
2462
- const listener = usePressResponder({stopPropagation: true});
1497
+ Scheduler.unstable_flushAll();
1498
+ document.body.removeChild(newContainer);
1499
+ });
1500
2464
- return <div ref={ref} listeners={listener} />;
2465
- };
1501
+ it(
1502
+ 'should only flush before outermost discrete event handler when mixing ' +
1503
+ 'event systems',
1504
+ async () => {
1505
+ const {useState} = React;
1506
2467
- container.addEventListener('pointerdown', pointerDownEvent);
2468
- ReactDOM.render(<Component />, container);
1507
+ const button = React.createRef();
1508
2470
- ref.current.dispatchEvent(
2471
- createEvent('pointerdown', {pointerType: 'mouse', button: 0}),
2472
- );
2473
- container.removeEventListener('pointerdown', pointerDownEvent);
2474
- expect(pointerDownEvent).toHaveBeenCalledTimes(0);
2475
- });
1509
+ const ops = [];
1510
2477
- it('has the correct press target when used with event hook', () => {
2478
- const ref = React.createRef();
2479
- const onPress = jest.fn();
2480
- const Component = () => {
2481
- const listener = usePressResponder({onPress});
1511
+ function MyComponent() {
1512
+ const [pressesCount, updatePressesCount] = useState(0);
1513
+ const [clicksCount, updateClicksCount] = useState(0);
1514
2483
- return (
2484
- <div>
2485
- <a href="#" ref={ref} listeners={listener} />
2486
- </div>
2487
- );
2488
- };
2489
- ReactDOM.render(<Component />, container);
1515
+ function handlePress() {
1516
+ // This dispatches a synchronous, discrete event in the legacy event
1517
+ // system. However, because it's nested inside the new event system,
1518
+ // its updates should not flush until the end of the outer handler.
1519
+ button.current.click();
1520
+ // Text context should not have changed
1521
+ ops.push(newContainer.textContent);
1522
+ updatePressesCount(pressesCount + 1);
1523
+ }
1524
2491
- ref.current.dispatchEvent(
2492
- createEvent('pointerdown', {pointerType: 'mouse', button: 0}),
2493
- );
2494
- ref.current.dispatchEvent(
2495
- createEvent('pointerup', {pointerType: 'mouse', button: 0}),
2496
- );
2497
- expect(onPress).toHaveBeenCalledTimes(1);
2498
- expect(onPress).toHaveBeenCalledWith(
2499
- expect.objectContaining({target: ref.current}),
1525
+ const listener = usePressResponder({
1526
+ onPress: handlePress,
1527
+ });
1528
+
1529
+ return (
1530
+ <div>
1531
+ <button
1532
+ listeners={listener}
1533
+ ref={button}
1534
+ onClick={() => updateClicksCount(clicksCount + 1)}>
1535
+ Presses: {pressesCount}, Clicks: {clicksCount}
1536
+ </button>
1537
+ </div>
1538
+ );
1539
+ }
1540
+
1541
+ const newContainer = document.createElement('div');
1542
+ document.body.appendChild(newContainer);
1543
+ const root = ReactDOM.unstable_createRoot(newContainer);
1544
+
1545
+ root.render(<MyComponent />);
1546
+ Scheduler.unstable_flushAll();
1547
+ expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
1548
+
1549
+ const target = button.current;
1550
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
1551
+ target.dispatchEvent(pointerup({timeStamp: 100}));
1552
+ target.dispatchEvent(click({timeStamp: 100}));
1553
+
1554
+ Scheduler.unstable_flushAll();
1555
+ expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
1556
+
1557
+ expect(ops).toEqual(['Presses: 0, Clicks: 0']);
1558
+ },
1559
);
2501
- });
1560
+
1561
+ it('should work correctly with stopPropagation set to true', () => {
1562
+ const ref = React.createRef();
1563
+ const pointerDownEvent = jest.fn();
1564
+
1565
+ const Component = () => {
1566
+ const listener = usePressResponder({stopPropagation: true});
1567
+ return <div ref={ref} listeners={listener} />;
1568
+ };
1569
+
1570
+ container.addEventListener('pointerdown', pointerDownEvent);
1571
+ ReactDOM.render(<Component />, container);
1572
+ dispatchPointerDown(ref.current);
1573
+ container.removeEventListener('pointerdown', pointerDownEvent);
1574
+ expect(pointerDownEvent).toHaveBeenCalledTimes(0);
1575
+ });
1576
+ }
1577
});
packages/react-events/src/dom/test-utils.js
+157
-76
@@ -15,7 +15,7 @@
15
* Change environment support for PointerEvent.
16
*/
17
18
-function hasPointerEvent(bool) {
18
+function hasPointerEvent() {
19
return global != null && global.PointerEvent != null;
20
}
21
@@ -57,23 +57,38 @@ const platform = {
57
* Mock native events
58
*/
59
60
-function createEvent(type, data) {
60
+function createEvent(type, data = {}) {
61
const event = document.createEvent('CustomEvent');
62
event.initCustomEvent(type, true, true);
63
+ event.clientX = data.x || 0;
64
+ event.clientY = data.y || 0;
65
+ event.x = data.x || 0;
66
+ event.y = data.y || 0;
67
if (data != null) {
64
- Object.entries(data).forEach(([key, value]) => {
65
- event[key] = value;
68
+ Object.keys(data).forEach(key => {
69
+ const value = data[key];
70
+ Object.defineProperty(event, key, {value});
71
});
72
}
73
return event;
74
}
75
71
-function createTouchEvent(type, data, id) {
76
+function createTouchEvent(type, data = {}, id) {
77
return createEvent(type, {
78
changedTouches: [
79
{
80
+ identifier: id,
81
+ clientX: data.x || 0,
82
+ clientY: data.y || 0,
83
...data,
84
+ },
85
+ ],
86
+ targetTouches: [
87
+ {
88
identifier: id,
89
+ clientX: 0 || data.x,
90
+ clientY: 0 || data.y,
91
+ ...data,
92
},
93
],
94
});
@@ -112,17 +127,45 @@ function gotpointercapture(data) {
127
}
128
129
function keydown(data) {
115
- return createKeyboardEvent('keydown', data);
130
+ return createEvent('keydown', data);
131
}
132
133
function keyup(data) {
119
- return createKeyboardEvent('keyup', data);
134
+ return createEvent('keyup', data);
135
}
136
137
function lostpointercapture(data) {
138
return createEvent('lostpointercapture', data);
139
}
140
141
+function mousedown(data) {
142
+ return createEvent('mousedown', data);
143
+}
144
+
145
+function mouseenter(data) {
146
+ return createEvent('mouseenter', data);
147
+}
148
+
149
+function mouseleave(data) {
150
+ return createEvent('mouseleave', data);
151
+}
152
+
153
+function mousemove(data) {
154
+ return createEvent('mousemove', data);
155
+}
156
+
157
+function mouseout(data) {
158
+ return createEvent('mouseout', data);
159
+}
160
+
161
+function mouseover(data) {
162
+ return createEvent('mouseover', data);
163
+}
164
+
165
+function mouseup(data) {
166
+ return createEvent('mouseup', data);
167
+}
168
+
169
function pointercancel(data) {
170
return createEvent('pointercancel', data);
171
}
@@ -155,32 +198,8 @@ function pointerup(data) {
198
return createEvent('pointerup', data);
199
}
200
158
-function mousedown(data) {
159
- return createEvent('mousedown', data);
160
-}
161
-
162
-function mouseenter(data) {
163
- return createEvent('mouseenter', data);
164
-}
165
-
166
-function mouseleave(data) {
167
- return createEvent('mouseleave', data);
168
-}
169
-
170
-function mousemove(data) {
171
- return createEvent('mousemove', data);
172
-}
173
-
174
-function mouseout(data) {
175
- return createEvent('mouseout', data);
176
-}
177
-
178
-function mouseover(data) {
179
- return createEvent('mouseover', data);
180
-}
181
-
182
-function mouseup(data) {
183
- return createEvent('mouseup', data);
201
+function scroll(data) {
202
+ return createEvent('scroll', data);
203
}
204
205
function touchcancel(data, id) {
@@ -264,15 +283,15 @@ function dispatchPointerHoverEnter(target, {relatedTarget, x, y} = {}) {
283
dispatch(pointerenter({pointerType, ...event}));
284
}
285
dispatch(mouseover(event));
267
- dispatch(mouseover(event));
286
+ dispatch(mouseenter(event));
287
}
288
270
-function dispatchPointerHoverMove(target, {from, to} = {}) {
289
+function dispatchPointerHoverMove(target, {x, y} = {}) {
290
const dispatch = arg => target.dispatchEvent(arg);
291
const button = -1;
292
const pointerId = 1;
293
const pointerType = 'mouse';
275
- function dispatchMove({x, y}) {
294
+ function dispatchMove() {
295
const event = {
296
button,
297
clientX: x,
@@ -285,8 +304,7 @@ function dispatchPointerHoverMove(target, {from, to} = {}) {
304
}
305
dispatch(mousemove(event));
306
}
288
- dispatchMove({x: from.x, y: from.y});
289
- dispatchMove({x: to.x, y: to.y});
307
+ dispatchMove();
308
}
309
310
function dispatchPointerHoverExit(target, {relatedTarget, x, y} = {}) {
@@ -309,77 +327,135 @@ function dispatchPointerHoverExit(target, {relatedTarget, x, y} = {}) {
327
dispatch(mouseleave(event));
328
}
329
312
-function dispatchPointerCancel(target, options) {
330
+function dispatchPointerCancel(target, {pointerType = 'mouse', ...rest} = {}) {
331
const dispatchEvent = arg => target.dispatchEvent(arg);
314
- dispatchEvent(pointercancel({pointerType: 'mouse'}));
315
- dispatchEvent(dragstart({pointerType: 'mouse'}));
332
+ if (hasPointerEvent()) {
333
+ dispatchEvent(pointercancel({pointerType, ...rest}));
334
+ } else {
335
+ if (pointerType === 'mouse') {
336
+ dispatchEvent(dragstart({...rest}));
337
+ } else {
338
+ dispatchEvent(touchcancel({...rest}));
339
+ }
340
+ }
341
}
342
318
-function dispatchPointerPressDown(
343
+function dispatchPointerDown(
344
target,
320
- {button = 0, pointerType = 'mouse'} = {},
345
+ {button = 0, pointerType = 'mouse', ...rest} = {},
346
) {
347
const dispatch = arg => target.dispatchEvent(arg);
348
const pointerId = 1;
324
- if (pointerType !== 'mouse') {
349
+ const pointerEvent = {button, pointerId, pointerType, ...rest};
350
+ const mouseEvent = {button, ...rest};
351
+ const touch = {...rest};
352
+
353
+ if (pointerType === 'mouse') {
354
if (hasPointerEvent()) {
326
- dispatch(pointerover({button, pointerId, pointerType}));
327
- dispatch(pointerenter({button, pointerId, pointerType}));
328
- dispatch(pointerdown({button, pointerId, pointerType}));
355
+ dispatch(pointerover(pointerEvent));
356
+ dispatch(pointerenter(pointerEvent));
357
}
330
- dispatch(touchstart(null, pointerId));
358
+ dispatch(mouseover(mouseEvent));
359
+ dispatch(mouseenter(mouseEvent));
360
if (hasPointerEvent()) {
332
- dispatch(gotpointercapture({button, pointerId, pointerType}));
361
+ dispatch(pointerdown(pointerEvent));
362
+ }
363
+ dispatch(mousedown(mouseEvent));
364
+ if (document.activeElement !== target) {
365
+ dispatch(focus());
366
}
367
} else {
368
if (hasPointerEvent()) {
336
- dispatch(pointerdown({button, pointerId, pointerType}));
369
+ dispatch(pointerover(pointerEvent));
370
+ dispatch(pointerenter(pointerEvent));
371
+ dispatch(pointerdown(pointerEvent));
372
}
338
- dispatch(mousedown({button}));
339
- if (document.activeElement !== target) {
340
- dispatch(focus({button}));
373
+ dispatch(touchstart(touch, pointerId));
374
+ if (hasPointerEvent()) {
375
+ dispatch(gotpointercapture(pointerEvent));
376
}
377
}
378
}
379
345
-function dispatchPointerPressRelease(
380
+function dispatchPointerUp(
381
target,
347
- {button = 0, pointerType = 'mouse'} = {},
382
+ {button = 0, pointerType = 'mouse', ...rest} = {},
383
) {
384
const dispatch = arg => target.dispatchEvent(arg);
385
const pointerId = 1;
351
- if (pointerType !== 'mouse') {
386
+ const pointerEvent = {button, pointerId, pointerType, ...rest};
387
+ const mouseEvent = {button, ...rest};
388
+ const touch = {...rest};
389
+
390
+ if (pointerType === 'mouse') {
391
if (hasPointerEvent()) {
353
- dispatch(pointerup({button, pointerId, pointerType}));
354
- dispatch(lostpointercapture({button, pointerId, pointerType}));
355
- dispatch(pointerout({button, pointerId, pointerType}));
356
- dispatch(pointerleave({button, pointerId, pointerType}));
357
- }
358
- dispatch(touchend(null, pointerId));
359
- dispatch(mouseover({button}));
360
- dispatch(mousemove({button}));
361
- dispatch(mousedown({button}));
362
- if (document.activeElement !== target) {
363
- dispatch(focus({button}));
392
+ dispatch(pointerup(pointerEvent));
393
}
365
- dispatch(mouseup({button}));
366
- dispatch(click({button}));
394
+ dispatch(mouseup(mouseEvent));
395
+ dispatch(click(mouseEvent));
396
} else {
397
if (hasPointerEvent()) {
369
- dispatch(pointerup({button, pointerId, pointerType}));
398
+ dispatch(pointerup(pointerEvent));
399
+ dispatch(lostpointercapture(pointerEvent));
400
+ dispatch(pointerout(pointerEvent));
401
+ dispatch(pointerleave(pointerEvent));
402
}
371
- dispatch(mouseup({button}));
372
- dispatch(click({button}));
403
+ dispatch(touchend(touch, pointerId));
404
+ dispatch(mouseover(mouseEvent));
405
+ dispatch(mousemove(mouseEvent));
406
+ dispatch(mousedown(mouseEvent));
407
+ if (document.activeElement !== target) {
408
+ dispatch(focus());
409
+ }
410
+ dispatch(mouseup(mouseEvent));
411
+ dispatch(click(mouseEvent));
412
+ }
413
+}
414
+
415
+function dispatchPointerMove(
416
+ target,
417
+ {button = 0, pointerType = 'mouse', ...rest} = {},
418
+) {
419
+ const dispatch = arg => target.dispatchEvent(arg);
420
+ const pointerId = 1;
421
+ const pointerEvent = {
422
+ button,
423
+ pointerId,
424
+ pointerType,
425
+ ...rest,
426
+ };
427
+ const mouseEvent = {
428
+ button,
429
+ ...rest,
430
+ };
431
+ const touch = {
432
+ ...rest,
433
+ };
434
+
435
+ if (hasPointerEvent()) {
436
+ dispatch(pointermove(pointerEvent));
437
+ }
438
+ if (pointerType === 'mouse') {
439
+ dispatch(mousemove(mouseEvent));
440
+ }
441
+ if (pointerType === 'touch') {
442
+ dispatch(touchmove(touch, pointerId));
443
}
444
}
445
446
function dispatchTouchTap(target) {
377
- dispatchPointerPressDown(target, {pointerType: 'touch'});
378
- dispatchPointerPressRelease(target, {pointerType: 'touch'});
447
+ dispatchPointerDown(target, {pointerType: 'touch'});
448
+ dispatchPointerUp(target, {pointerType: 'touch'});
449
+}
450
+
451
+function dispatchMouseTap(target) {
452
+ dispatchPointerDown(target, {pointerType: 'mouse'});
453
+ dispatchPointerUp(target, {pointerType: 'mouse'});
454
}
455
456
module.exports = {
457
blur,
458
+ click,
459
focus,
460
createEvent,
461
dispatchLongPressContextMenu,
@@ -389,11 +465,16 @@ module.exports = {
465
dispatchPointerHoverEnter,
466
dispatchPointerHoverExit,
467
dispatchPointerHoverMove,
392
- dispatchPointerPressDown,
393
- dispatchPointerPressRelease,
468
+ dispatchPointerMove,
469
+ dispatchPointerDown,
470
+ dispatchPointerUp,
471
dispatchTouchTap,
472
+ dispatchMouseTap,
473
keydown,
474
keyup,
475
+ scroll,
476
+ pointerdown,
477
+ pointerup,
478
platform,
479
hasPointerEvent,
480
setPointerEvent,