Skip to content

Commit a5e951d

Browse files
authored
[react-interactions] Event testing library improvements (#17614)
Introduces a state machine around pointer events to produce more accurate mock touch events. This allows multi-touch unit tests to be written entirely in terms of mock pointer interactions, while producing the expected 'changedTouches', 'targetTouches', and 'touches' fields for mock touch events.
1 parent 95056b6 commit a5e951d

23 files changed

+631
-456
lines changed

packages/react-interactions/accessibility/src/__tests__/FocusContain-test.internal.js

+34-24
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@
77
* @flow
88
*/
99

10-
import {createEventTarget} from 'react-interactions/events/src/dom/testing-library';
10+
import {createEventTarget} from 'react-interactions/events/src/dom/event-testing-library';
1111

1212
let React;
1313
let ReactFeatureFlags;
1414
let FocusContain;
1515
let tabbableScopeQuery;
1616

17+
function tabNext(target) {
18+
target.keydown({key: 'Tab'});
19+
target.keyup({key: 'Tab'});
20+
}
21+
22+
function tabPrevious(target) {
23+
target.keydown({key: 'Tab', shiftKey: true});
24+
target.keyup({key: 'Tab', shiftKey: true});
25+
}
26+
1727
describe('FocusContain', () => {
1828
beforeEach(() => {
1929
jest.resetModules();
@@ -59,13 +69,13 @@ describe('FocusContain', () => {
5969

6070
ReactDOM.render(<Test />, container);
6171
expect(document.activeElement).toBe(inputRef.current);
62-
createEventTarget(document.activeElement).tabNext();
72+
tabNext(createEventTarget(document.activeElement));
6373
expect(document.activeElement).toBe(buttonRef.current);
64-
createEventTarget(document.activeElement).tabNext();
74+
tabNext(createEventTarget(document.activeElement));
6575
expect(document.activeElement).toBe(divRef.current);
66-
createEventTarget(document.activeElement).tabNext();
76+
tabNext(createEventTarget(document.activeElement));
6777
expect(document.activeElement).toBe(button2Ref.current);
68-
createEventTarget(document.activeElement).tabPrevious();
78+
tabPrevious(createEventTarget(document.activeElement));
6979
expect(document.activeElement).toBe(divRef.current);
7080
});
7181

@@ -90,15 +100,15 @@ describe('FocusContain', () => {
90100

91101
ReactDOM.render(<Test />, container);
92102
buttonRef.current.focus();
93-
createEventTarget(document.activeElement).tabNext();
103+
tabNext(createEventTarget(document.activeElement));
94104
expect(document.activeElement).toBe(button2Ref.current);
95-
createEventTarget(document.activeElement).tabNext();
105+
tabNext(createEventTarget(document.activeElement));
96106
expect(document.activeElement).toBe(buttonRef.current);
97-
createEventTarget(document.activeElement).tabNext();
107+
tabNext(createEventTarget(document.activeElement));
98108
expect(document.activeElement).toBe(button2Ref.current);
99-
createEventTarget(document.activeElement).tabPrevious();
109+
tabPrevious(createEventTarget(document.activeElement));
100110
expect(document.activeElement).toBe(buttonRef.current);
101-
createEventTarget(document.activeElement).tabPrevious();
111+
tabPrevious(createEventTarget(document.activeElement));
102112
expect(document.activeElement).toBe(button2Ref.current);
103113
// Focus should be restored to the contained area
104114
const rAF = window.requestAnimationFrame;
@@ -132,15 +142,15 @@ describe('FocusContain', () => {
132142

133143
ReactDOM.render(<Test />, container);
134144
expect(document.activeElement).toBe(buttonRef.current);
135-
createEventTarget(document.activeElement).tabNext();
145+
tabNext(createEventTarget(document.activeElement));
136146
expect(document.activeElement).toBe(button2Ref.current);
137-
createEventTarget(document.activeElement).tabNext();
147+
tabNext(createEventTarget(document.activeElement));
138148
expect(document.activeElement).toBe(button3Ref.current);
139-
createEventTarget(document.activeElement).tabNext();
149+
tabNext(createEventTarget(document.activeElement));
140150
expect(document.activeElement).toBe(button4Ref.current);
141-
createEventTarget(document.activeElement).tabPrevious();
151+
tabPrevious(createEventTarget(document.activeElement));
142152
expect(document.activeElement).toBe(button3Ref.current);
143-
createEventTarget(document.activeElement).tabPrevious();
153+
tabPrevious(createEventTarget(document.activeElement));
144154
expect(document.activeElement).toBe(button2Ref.current);
145155
});
146156

@@ -167,13 +177,13 @@ describe('FocusContain', () => {
167177

168178
ReactDOM.render(<Test />, container);
169179
expect(document.activeElement).toBe(button2Ref.current);
170-
createEventTarget(document.activeElement).tabNext();
180+
tabNext(createEventTarget(document.activeElement));
171181
expect(document.activeElement).toBe(button3Ref.current);
172-
createEventTarget(document.activeElement).tabNext();
182+
tabNext(createEventTarget(document.activeElement));
173183
expect(document.activeElement).toBe(button2Ref.current);
174-
createEventTarget(document.activeElement).tabPrevious();
184+
tabPrevious(createEventTarget(document.activeElement));
175185
expect(document.activeElement).toBe(button3Ref.current);
176-
createEventTarget(document.activeElement).tabPrevious();
186+
tabPrevious(createEventTarget(document.activeElement));
177187
expect(document.activeElement).toBe(button2Ref.current);
178188
});
179189

@@ -213,15 +223,15 @@ describe('FocusContain', () => {
213223
ReactDOM.render(<Test />, container);
214224
buttonRef.current.focus();
215225
expect(document.activeElement).toBe(buttonRef.current);
216-
createEventTarget(document.activeElement).tabNext();
226+
tabNext(createEventTarget(document.activeElement));
217227
expect(document.activeElement).toBe(button2Ref.current);
218-
createEventTarget(document.activeElement).tabNext();
228+
tabNext(createEventTarget(document.activeElement));
219229
expect(document.activeElement).toBe(button3Ref.current);
220-
createEventTarget(document.activeElement).tabNext();
230+
tabNext(createEventTarget(document.activeElement));
221231
expect(document.activeElement).toBe(button4Ref.current);
222-
createEventTarget(document.activeElement).tabPrevious();
232+
tabPrevious(createEventTarget(document.activeElement));
223233
expect(document.activeElement).toBe(button3Ref.current);
224-
createEventTarget(document.activeElement).tabPrevious();
234+
tabPrevious(createEventTarget(document.activeElement));
225235
expect(document.activeElement).toBe(button2Ref.current);
226236
});
227237
});

packages/react-interactions/accessibility/src/__tests__/FocusGroup-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import {createEventTarget} from 'react-interactions/events/src/dom/testing-library';
10+
import {createEventTarget} from 'react-interactions/events/src/dom/event-testing-library';
1111
import {emulateBrowserTab} from '../shared/emulateBrowserTab';
1212

1313
let React;

packages/react-interactions/accessibility/src/__tests__/FocusTable-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import {createEventTarget} from 'react-interactions/events/src/dom/testing-library';
10+
import {createEventTarget} from 'react-interactions/events/src/dom/event-testing-library';
1111
import {emulateBrowserTab} from '../shared/emulateBrowserTab';
1212

1313
let React;

packages/react-interactions/accessibility/src/shared/emulateBrowserTab.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import {createEventTarget} from 'react-interactions/events/src/dom/testing-library';
12+
import {createEventTarget} from 'react-interactions/events/src/dom/event-testing-library';
1313

1414
// This function is used by the a11y modules for testing
1515
export function emulateBrowserTab(backwards: boolean): void {

packages/react-interactions/events/src/dom/__tests__/ContextMenu-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
createEventTarget,
1515
platform,
1616
setPointerEvent,
17-
} from '../testing-library';
17+
} from '../event-testing-library';
1818

1919
let React;
2020
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/Focus-test.internal.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
'use strict';
1111

12-
import {createEventTarget, setPointerEvent, platform} from '../testing-library';
12+
import {
13+
createEventTarget,
14+
setPointerEvent,
15+
platform,
16+
} from '../event-testing-library';
1317

1418
let React;
1519
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/FocusWithin-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import {createEventTarget, setPointerEvent} from '../testing-library';
12+
import {createEventTarget, setPointerEvent} from '../event-testing-library';
1313

1414
let React;
1515
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/Hover-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import {createEventTarget, setPointerEvent} from '../testing-library';
12+
import {createEventTarget, setPointerEvent} from '../event-testing-library';
1313

1414
let React;
1515
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/Keyboard-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ let ReactFeatureFlags;
1414
let ReactDOM;
1515
let useKeyboard;
1616

17-
import {createEventTarget} from '../testing-library';
17+
import {createEventTarget} from '../event-testing-library';
1818

1919
function initializeModules(hasPointerEvents) {
2020
jest.resetModules();

packages/react-interactions/events/src/dom/__tests__/MixedResponders-test-internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import {createEventTarget} from '../testing-library';
12+
import {createEventTarget} from '../event-testing-library';
1313

1414
let React;
1515
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/Press-test.internal.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import {
1414
buttonsType,
1515
createEventTarget,
1616
describeWithPointerEvent,
17+
resetActivePointers,
1718
setPointerEvent,
18-
} from '../testing-library';
19+
} from '../event-testing-library';
1920

2021
let React;
2122
let ReactFeatureFlags;
@@ -47,6 +48,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
4748
ReactDOM.render(null, container);
4849
document.body.removeChild(container);
4950
container = null;
51+
resetActivePointers();
5052
});
5153

5254
describe('disabled', () => {

packages/react-interactions/events/src/dom/__tests__/PressLegacy-test.internal.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import {
1313
buttonType,
1414
buttonsType,
1515
createEventTarget,
16+
resetActivePointers,
1617
setPointerEvent,
17-
} from '../testing-library';
18+
} from '../event-testing-library';
1819

1920
let React;
2021
let ReactFeatureFlags;
@@ -59,6 +60,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
5960
ReactDOM.render(null, container);
6061
document.body.removeChild(container);
6162
container = null;
63+
resetActivePointers();
6264
});
6365

6466
describe('disabled', () => {

packages/react-interactions/events/src/dom/__tests__/Scroll-test.internal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import {createEventTarget, setPointerEvent} from '../testing-library';
12+
import {createEventTarget, setPointerEvent} from '../event-testing-library';
1313

1414
let React;
1515
let ReactFeatureFlags;

packages/react-interactions/events/src/dom/__tests__/Tap-test.internal.js

+17-23
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
describeWithPointerEvent,
1717
setPointerEvent,
1818
testWithPointerType,
19-
} from '../testing-library';
19+
resetActivePointers,
20+
} from '../event-testing-library';
2021

2122
let React;
2223
let ReactFeatureFlags;
@@ -82,6 +83,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
8283
ReactDOM.render(null, container);
8384
document.body.removeChild(container);
8485
container = null;
86+
resetActivePointers();
8587
});
8688

8789
test('supports repeated use', () => {
@@ -295,12 +297,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
295297
const buttons = buttonsType.primary;
296298
target.pointerdown({button, buttons, pointerId: 1, pointerType});
297299
expect(onTapStart).toHaveBeenCalledTimes(1);
298-
if (hasPointerEvents) {
299-
target.pointerdown({button, buttons, pointerId: 2, pointerType});
300-
} else {
301-
// TouchEvents
302-
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
303-
}
300+
target.pointerdown({button, buttons, pointerId: 2, pointerType});
304301
expect(onTapStart).toHaveBeenCalledTimes(1);
305302
});
306303

@@ -313,28 +310,28 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
313310
buttons: buttonsType.secondary,
314311
pointerType,
315312
});
316-
target.pointerup();
313+
target.pointerup({pointerType});
317314
// middle-click
318315
target.pointerdown({
319316
button: buttonType.auxiliary,
320317
buttons: buttonsType.auxiliary,
321318
pointerType,
322319
});
323-
target.pointerup();
320+
target.pointerup({pointerType});
324321
// virtual middle-click with misleading 'buttons' value
325322
target.pointerdown({
326323
button: buttonType.auxiliary,
327324
buttons: 0,
328325
pointerType,
329326
});
330-
target.pointerup();
327+
target.pointerup({pointerType});
331328
// pen eraser
332329
target.pointerdown({
333330
button: buttonType.eraser,
334331
buttons: buttonsType.eraser,
335332
pointerType,
336333
});
337-
target.pointerup();
334+
target.pointerup({pointerType});
338335
}
339336
// alt-click
340337
target.pointerdown({
@@ -343,31 +340,31 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
343340
altKey: true,
344341
pointerType,
345342
});
346-
target.pointerup();
343+
target.pointerup({pointerType});
347344
// ctrl-click
348345
target.pointerdown({
349346
button: buttonType.primary,
350347
buttons: buttonsType.primary,
351348
ctrlKey: true,
352349
pointerType,
353350
});
354-
target.pointerup();
351+
target.pointerup({pointerType});
355352
// meta-click
356353
target.pointerdown({
357354
button: buttonType.primary,
358355
buttons: buttonsType.primary,
359356
metaKey: true,
360357
pointerType,
361358
});
362-
target.pointerup();
359+
target.pointerup({pointerType});
363360
// shift-click
364361
target.pointerdown({
365362
button: buttonType.primary,
366363
buttons: buttonsType.primary,
367364
shiftKey: true,
368365
pointerType,
369366
});
370-
target.pointerup();
367+
target.pointerup({pointerType});
371368

372369
expect(onTapStart).toHaveBeenCalledTimes(0);
373370
});
@@ -565,8 +562,10 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
565562
testWithPointerType('requires activation', pointerType => {
566563
const target = createEventTarget(ref.current);
567564
target.setBoundingClientRect(rect);
568-
target.pointerhover({pointerType, ...coordinates});
569-
target.pointermove({pointerType, ...coordinates});
565+
if (pointerType !== 'touch') {
566+
target.pointerhover({pointerType, ...coordinates});
567+
target.pointermove({pointerType, ...coordinates});
568+
}
570569
expect(onTapUpdate).not.toBeCalled();
571570
});
572571

@@ -771,12 +770,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
771770
const button = buttonType.primary;
772771
const buttons = buttonsType.primary;
773772
target.pointerdown({button, buttons, pointerId: 1, pointerType});
774-
if (hasPointerEvents) {
775-
target.pointerdown({button, buttons, pointerId: 2, pointerType});
776-
} else {
777-
// TouchEvents
778-
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
779-
}
773+
target.pointerdown({button, buttons, pointerId: 2, pointerType});
780774
expect(onTapCancel).toHaveBeenCalledTimes(1);
781775
});
782776

0 commit comments

Comments
 (0)