Skip to content

Commit cb15f18

Browse files
authored
[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
1 parent 4ef2696 commit cb15f18

File tree

4 files changed

+158
-67
lines changed

4 files changed

+158
-67
lines changed

packages/react-events/src/dom/testing-library/domEnvironment.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
* Change environment support for PointerEvent.
1414
*/
1515

16+
const emptyFunction = function() {};
17+
1618
export function hasPointerEvent() {
1719
return global != null && global.PointerEvent != null;
1820
}
1921

2022
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;
2227
}
2328

2429
/**

packages/react-events/src/dom/testing-library/domEventSequences.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,18 @@ export function pointermove(target, payload) {
138138
const dispatch = arg => target.dispatchEvent(arg);
139139
const pointerType = getPointerType(payload);
140140
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+
);
145147
} else {
146-
dispatch(domEvents.touchmove(payload));
148+
if (pointerType === 'mouse') {
149+
dispatch(domEvents.mousemove(payload));
150+
} else {
151+
dispatch(domEvents.touchmove(payload));
152+
}
147153
}
148154
}
149155

packages/react-events/src/dom/testing-library/domEvents.js

Lines changed: 116 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ function createPointerEvent(
6464
altKey = false,
6565
buttons = buttonsType.none,
6666
ctrlKey = false,
67+
detail = 1,
6768
height,
6869
metaKey = false,
6970
movementX = 0,
@@ -76,6 +77,8 @@ function createPointerEvent(
7677
pressure = 0,
7778
preventDefault = emptyFunction,
7879
pointerType = 'mouse',
80+
screenX,
81+
screenY,
7982
shiftKey = false,
8083
tangentialPressure = 0,
8184
tiltX = 0,
@@ -87,22 +90,19 @@ function createPointerEvent(
8790
} = {},
8891
) {
8992
const modifierState = {altKey, ctrlKey, metaKey, shiftKey};
93+
const isMouse = pointerType === 'mouse';
9094

9195
return createEvent(type, {
9296
altKey,
9397
buttons,
9498
clientX: x,
9599
clientY: y,
96100
ctrlKey,
101+
detail,
97102
getModifierState(keyArg) {
98103
createGetModifierState(keyArg, modifierState);
99104
},
100-
height:
101-
pointerType === 'mouse'
102-
? 1
103-
: height != null
104-
? height
105-
: defaultPointerSize,
105+
height: isMouse ? 1 : height != null ? height : defaultPointerSize,
106106
metaKey,
107107
movementX,
108108
movementY,
@@ -114,15 +114,16 @@ function createPointerEvent(
114114
pointerType,
115115
pressure,
116116
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,
119121
shiftKey,
120122
tangentialPressure,
121123
tiltX,
122124
tiltY,
123125
twist,
124-
width:
125-
pointerType === 'mouse' ? 1 : width != null ? width : defaultPointerSize,
126+
width: isMouse ? 1 : width != null ? width : defaultPointerSize,
126127
});
127128
}
128129

@@ -158,6 +159,7 @@ function createMouseEvent(
158159
altKey = false,
159160
buttons = buttonsType.none,
160161
ctrlKey = false,
162+
detail = 1,
161163
metaKey = false,
162164
movementX = 0,
163165
movementY = 0,
@@ -166,81 +168,107 @@ function createMouseEvent(
166168
pageX,
167169
pageY,
168170
preventDefault = emptyFunction,
171+
screenX,
172+
screenY,
169173
shiftKey = false,
170174
x = 0,
171175
y = 0,
172176
} = {},
173-
virtual = false,
174177
) {
175178
const modifierState = {altKey, ctrlKey, metaKey, shiftKey};
176179

177180
return createEvent(type, {
178181
altKey,
179182
buttons,
180-
clientX: virtual ? 0 : x,
181-
clientY: virtual ? 0 : y,
183+
clientX: x,
184+
clientY: y,
182185
ctrlKey,
183-
detail: virtual ? 0 : 1,
186+
detail,
184187
getModifierState(keyArg) {
185188
createGetModifierState(keyArg, modifierState);
186189
},
187190
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,
194197
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,
197200
shiftKey,
198201
});
199202
}
200203

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+
);
232256

233-
const activeTouch = type !== 'touchend' ? [touch] : null;
257+
const activeTouches = type !== 'touchend' ? touches : null;
234258

235259
return createEvent(type, {
236260
altKey,
237-
changedTouches: [touch],
261+
changedTouches: touches,
238262
ctrlKey,
263+
detail: 0,
239264
metaKey,
240265
preventDefault,
241266
shiftKey,
242-
targetTouches: activeTouch,
243-
touches: activeTouch,
267+
sourceCapabilities: {
268+
firesTouchEvents: true,
269+
},
270+
targetTouches: activeTouches,
271+
touches: activeTouches,
244272
});
245273
}
246274

@@ -253,11 +281,24 @@ export function blur({relatedTarget} = {}) {
253281
}
254282

255283
export function click(payload) {
256-
return createMouseEvent('click', payload, false);
284+
return createMouseEvent('click', payload);
257285
}
258286

259287
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+
});
261302
}
262303

263304
export function contextmenu(payload) {
@@ -301,11 +342,24 @@ export function lostpointercapture(payload) {
301342
}
302343

303344
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+
});
305359
}
306360

307361
export function pointerdown(payload) {
308-
const isTouch = payload != null && payload.pointerType === 'mouse';
362+
const isTouch = payload != null && payload.pointerType === 'touch';
309363
return createPointerEvent('pointerdown', {
310364
buttons: buttonsType.primary,
311365
pressure: isTouch ? 1 : 0.5,
@@ -337,6 +391,7 @@ export function pointerup(payload) {
337391
return createPointerEvent('pointerup', {
338392
...payload,
339393
buttons: buttonsType.none,
394+
pressure: 0,
340395
});
341396
}
342397

packages/react-events/src/dom/testing-library/index.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,35 @@ const createEventTarget = node => ({
109109
},
110110
});
111111

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+
112135
export {
113136
buttonsType,
114137
createEventTarget,
138+
describeWithPointerEvent,
115139
platform,
116140
hasPointerEvent,
117141
setPointerEvent,
142+
testWithPointerType,
118143
};

0 commit comments

Comments
 (0)