@samitouri / QOS-React-2 / commits / cb15f18dc1

[react-events] Improve mock event object accuracy (#16590)

* Better simulation for pointercancel * Fix pressure values for different pointers * Add describe/test helpers for pointer events

Nicolas Gallagher committed Aug 27, 2019 at 15:45 UTC cb15f18dc1a3a28e67c8fe1101e55b5033d12e96
4 files changed +158 -67
packages/react-events/src/dom/testing-library/domEnvironment.js
+6 -1
@@ -13,12 +13,17 @@
13 * Change environment support for PointerEvent.
14 */
15
16 +const emptyFunction = function() {};
17 +
18 export function hasPointerEvent() {
19 return global != null && global.PointerEvent != null;
20 }
21
22 export function setPointerEvent(bool) {
21 - global.PointerEvent = bool ? function() {} : undefined;
23 + const mock = bool ? emptyFunction : undefined;
24 + global.PointerEvent = mock;
25 + global.HTMLElement.prototype.setPointerCapture = mock;
26 + global.HTMLElement.prototype.releasePointerCapture = mock;
27 }
28
29 /**
packages/react-events/src/dom/testing-library/domEventSequences.js
+11 -5
@@ -138,12 +138,18 @@ export function pointermove(target, payload) {
138 const dispatch = arg => target.dispatchEvent(arg);
139 const pointerType = getPointerType(payload);
140 if (hasPointerEvent()) {
141 - dispatch(domEvents.pointermove(payload));
142 - }
143 - if (pointerType === 'mouse') {
144 - dispatch(domEvents.mousemove(payload));
141 + dispatch(
142 + domEvents.pointermove({
143 + pressure: pointerType === 'touch' ? 1 : 0.5,
144 + ...payload,
145 + }),
146 + );
147 } else {
146 - dispatch(domEvents.touchmove(payload));
148 + if (pointerType === 'mouse') {
149 + dispatch(domEvents.mousemove(payload));
150 + } else {
151 + dispatch(domEvents.touchmove(payload));
152 + }
153 }
154 }
155
packages/react-events/src/dom/testing-library/domEvents.js
+116 -61
@@ -64,6 +64,7 @@ function createPointerEvent(
64 altKey = false,
65 buttons = buttonsType.none,
66 ctrlKey = false,
67 + detail = 1,
68 height,
69 metaKey = false,
70 movementX = 0,
@@ -76,6 +77,8 @@ function createPointerEvent(
77 pressure = 0,
78 preventDefault = emptyFunction,
79 pointerType = 'mouse',
80 + screenX,
81 + screenY,
82 shiftKey = false,
83 tangentialPressure = 0,
84 tiltX = 0,
@@ -87,6 +90,7 @@ function createPointerEvent(
90 } = {},
91 ) {
92 const modifierState = {altKey, ctrlKey, metaKey, shiftKey};
93 + const isMouse = pointerType === 'mouse';
94
95 return createEvent(type, {
96 altKey,
@@ -94,15 +98,11 @@ function createPointerEvent(
98 clientX: x,
99 clientY: y,
100 ctrlKey,
101 + detail,
102 getModifierState(keyArg) {
103 createGetModifierState(keyArg, modifierState);
104 },
100 - height:
101 - pointerType === 'mouse'
102 - ? 1
103 - : height != null
104 - ? height
105 - : defaultPointerSize,
105 + height: isMouse ? 1 : height != null ? height : defaultPointerSize,
106 metaKey,
107 movementX,
108 movementY,
@@ -114,15 +114,16 @@ function createPointerEvent(
114 pointerType,
115 pressure,
116 preventDefault,
117 - screenX: x,
118 - screenY: y + defaultBrowserChromeSize,
117 + releasePointerCapture: emptyFunction,
118 + screenX: screenX === 0 ? screenX : x,
119 + screenY: screenY === 0 ? screenY : y + defaultBrowserChromeSize,
120 + setPointerCapture: emptyFunction,
121 shiftKey,
122 tangentialPressure,
123 tiltX,
124 tiltY,
125 twist,
124 - width:
125 - pointerType === 'mouse' ? 1 : width != null ? width : defaultPointerSize,
126 + width: isMouse ? 1 : width != null ? width : defaultPointerSize,
127 });
128 }
129
@@ -158,6 +159,7 @@ function createMouseEvent(
159 altKey = false,
160 buttons = buttonsType.none,
161 ctrlKey = false,
162 + detail = 1,
163 metaKey = false,
164 movementX = 0,
165 movementY = 0,
@@ -166,81 +168,107 @@ function createMouseEvent(
168 pageX,
169 pageY,
170 preventDefault = emptyFunction,
171 + screenX,
172 + screenY,
173 shiftKey = false,
174 x = 0,
175 y = 0,
176 } = {},
173 - virtual = false,
177 ) {
178 const modifierState = {altKey, ctrlKey, metaKey, shiftKey};
179
180 return createEvent(type, {
181 altKey,
182 buttons,
180 - clientX: virtual ? 0 : x,
181 - clientY: virtual ? 0 : y,
183 + clientX: x,
184 + clientY: y,
185 ctrlKey,
183 - detail: virtual ? 0 : 1,
186 + detail,
187 getModifierState(keyArg) {
188 createGetModifierState(keyArg, modifierState);
189 },
190 metaKey,
188 - movementX: virtual ? 0 : movementX,
189 - movementY: virtual ? 0 : movementY,
190 - offsetX: virtual ? 0 : offsetX,
191 - offsetY: virtual ? 0 : offsetY,
192 - pageX: virtual ? 0 : pageX || x,
193 - pageY: virtual ? 0 : pageY || y,
191 + movementX,
192 + movementY,
193 + offsetX,
194 + offsetY,
195 + pageX: pageX || x,
196 + pageY: pageY || y,
197 preventDefault,
195 - screenX: virtual ? 0 : x,
196 - screenY: virtual ? 0 : y + defaultBrowserChromeSize,
198 + screenX: screenX === 0 ? screenX : x,
199 + screenY: screenY === 0 ? screenY : y + defaultBrowserChromeSize,
200 shiftKey,
201 });
202 }
203
201 -function createTouchEvent(
202 - type,
203 - {
204 - altKey = false,
205 - ctrlKey = false,
206 - height = defaultPointerSize,
207 - metaKey = false,
208 - pageX,
209 - pageY,
210 - pointerId = 1,
211 - preventDefault = emptyFunction,
212 - shiftKey = false,
213 - twist = 0,
214 - width = defaultPointerSize,
215 - x = 0,
216 - y = 0,
217 - } = {},
218 -) {
219 - const touch = {
220 - clientX: x,
221 - clientY: y,
222 - force: 1,
223 - identifier: pointerId,
224 - pageX: pageX || x,
225 - pageY: pageY || y,
226 - radiusX: width / 2,
227 - radiusY: height / 2,
228 - rotationAngle: twist,
229 - screenX: x,
230 - screenY: y + defaultBrowserChromeSize,
231 - };
204 +function createTouchEvent(type, payload) {
205 + const touchesPayload = Array.isArray(payload) ? payload : [payload];
206 + const firstTouch = touchesPayload[0];
207 + let altKey = false;
208 + let ctrlKey = false;
209 + let metaKey = false;
210 + let preventDefault = emptyFunction;
211 + let shiftKey = false;
212 + if (firstTouch != null) {
213 + if (firstTouch.altKey != null) {
214 + altKey = firstTouch.altKey;
215 + }
216 + if (firstTouch.ctrlKey != null) {
217 + ctrlKey = firstTouch.ctrlKey;
218 + }
219 + if (firstTouch.metaKey != null) {
220 + metaKey = firstTouch.metaKey;
221 + }
222 + if (firstTouch.preventDefault != null) {
223 + preventDefault = firstTouch.preventDefault;
224 + }
225 + if (firstTouch.shiftKey != null) {
226 + shiftKey = firstTouch.shiftKey;
227 + }
228 + }
229 +
230 + const touches = touchesPayload.map(
231 + ({
232 + height = defaultPointerSize,
233 + pageX,
234 + pageY,
235 + pointerId = 1,
236 + twist = 0,
237 + width = defaultPointerSize,
238 + x = 0,
239 + y = 0,
240 + } = {}) => {
241 + return {
242 + clientX: x,
243 + clientY: y,
244 + force: 1,
245 + identifier: pointerId,
246 + pageX: pageX || x,
247 + pageY: pageY || y,
248 + radiusX: width / 2,
249 + radiusY: height / 2,
250 + rotationAngle: twist,
251 + screenX: x,
252 + screenY: y + defaultBrowserChromeSize,
253 + };
254 + },
255 + );
256
233 - const activeTouch = type !== 'touchend' ? [touch] : null;
257 + const activeTouches = type !== 'touchend' ? touches : null;
258
259 return createEvent(type, {
260 altKey,
237 - changedTouches: [touch],
261 + changedTouches: touches,
262 ctrlKey,
263 + detail: 0,
264 metaKey,
265 preventDefault,
266 shiftKey,
242 - targetTouches: activeTouch,
243 - touches: activeTouch,
267 + sourceCapabilities: {
268 + firesTouchEvents: true,
269 + },
270 + targetTouches: activeTouches,
271 + touches: activeTouches,
272 });
273 }
274
@@ -253,11 +281,24 @@ export function blur({relatedTarget} = {}) {
281 }
282
283 export function click(payload) {
256 - return createMouseEvent('click', payload, false);
284 + return createMouseEvent('click', payload);
285 }
286
287 export function virtualclick(payload) {
260 - return createMouseEvent('click', payload, true);
288 + return createMouseEvent('click', {
289 + ...payload,
290 + buttons: 0,
291 + detail: 0,
292 + height: 1,
293 + pageX: 0,
294 + pageY: 0,
295 + pressure: 0,
296 + screenX: 0,
297 + screenY: 0,
298 + width: 1,
299 + x: 0,
300 + y: 0,
301 + });
302 }
303
304 export function contextmenu(payload) {
@@ -301,11 +342,24 @@ export function lostpointercapture(payload) {
342 }
343
344 export function pointercancel(payload) {
304 - return createPointerEvent('pointercancel', payload);
345 + return createPointerEvent('pointercancel', {
346 + ...payload,
347 + buttons: 0,
348 + detail: 0,
349 + height: 1,
350 + pageX: 0,
351 + pageY: 0,
352 + pressure: 0,
353 + screenX: 0,
354 + screenY: 0,
355 + width: 1,
356 + x: 0,
357 + y: 0,
358 + });
359 }
360
361 export function pointerdown(payload) {
308 - const isTouch = payload != null && payload.pointerType === 'mouse';
362 + const isTouch = payload != null && payload.pointerType === 'touch';
363 return createPointerEvent('pointerdown', {
364 buttons: buttonsType.primary,
365 pressure: isTouch ? 1 : 0.5,
@@ -337,6 +391,7 @@ export function pointerup(payload) {
391 return createPointerEvent('pointerup', {
392 ...payload,
393 buttons: buttonsType.none,
394 + pressure: 0,
395 });
396 }
397
packages/react-events/src/dom/testing-library/index.js
+25
@@ -109,10 +109,35 @@ const createEventTarget = node => ({
109 },
110 });
111
112 +function describeWithPointerEvent(message, describeFn) {
113 + const pointerEvent = 'PointerEvent';
114 + const fallback = 'MouseEvent/TouchEvent';
115 + describe.each`
116 + value | name
117 + ${true} | ${pointerEvent}
118 + ${false} | ${fallback}
119 + `(`${message}: $name`, entry => {
120 + const hasPointerEvents = entry.value;
121 + setPointerEvent(hasPointerEvents);
122 + describeFn(hasPointerEvents);
123 + });
124 +}
125 +
126 +function testWithPointerType(message, testFn) {
127 + const table = hasPointerEvent()
128 + ? ['mouse', 'touch', 'pen']
129 + : ['mouse', 'touch'];
130 + test.each(table)(`${message}: %s`, pointerType => {
131 + testFn(pointerType);
132 + });
133 +}
134 +
135 export {
136 buttonsType,
137 createEventTarget,
138 + describeWithPointerEvent,
139 platform,
140 hasPointerEvent,
141 setPointerEvent,
142 + testWithPointerType,
143 };