Skip to content

Commit

Permalink
[react-interactions] Event testing library improvements (#17614)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
necolas authored Dec 18, 2019
1 parent 95056b6 commit a5e951d
Show file tree
Hide file tree
Showing 23 changed files with 631 additions and 456 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@
* @flow
*/

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

let React;
let ReactFeatureFlags;
let FocusContain;
let tabbableScopeQuery;

function tabNext(target) {
target.keydown({key: 'Tab'});
target.keyup({key: 'Tab'});
}

function tabPrevious(target) {
target.keydown({key: 'Tab', shiftKey: true});
target.keyup({key: 'Tab', shiftKey: true});
}

describe('FocusContain', () => {
beforeEach(() => {
jest.resetModules();
Expand Down Expand Up @@ -59,13 +69,13 @@ describe('FocusContain', () => {

ReactDOM.render(<Test />, container);
expect(document.activeElement).toBe(inputRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(buttonRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(divRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(divRef.current);
});

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

ReactDOM.render(<Test />, container);
buttonRef.current.focus();
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(buttonRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(buttonRef.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
// Focus should be restored to the contained area
const rAF = window.requestAnimationFrame;
Expand Down Expand Up @@ -132,15 +142,15 @@ describe('FocusContain', () => {

ReactDOM.render(<Test />, container);
expect(document.activeElement).toBe(buttonRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button4Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
});

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

ReactDOM.render(<Test />, container);
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
});

Expand Down Expand Up @@ -213,15 +223,15 @@ describe('FocusContain', () => {
ReactDOM.render(<Test />, container);
buttonRef.current.focus();
expect(document.activeElement).toBe(buttonRef.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabNext();
tabNext(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button4Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button3Ref.current);
createEventTarget(document.activeElement).tabPrevious();
tabPrevious(createEventTarget(document.activeElement));
expect(document.activeElement).toBe(button2Ref.current);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

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

let React;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

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

let React;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

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

// This function is used by the a11y modules for testing
export function emulateBrowserTab(backwards: boolean): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
createEventTarget,
platform,
setPointerEvent,
} from '../testing-library';
} from '../event-testing-library';

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@

'use strict';

import {createEventTarget, setPointerEvent, platform} from '../testing-library';
import {
createEventTarget,
setPointerEvent,
platform,
} from '../event-testing-library';

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

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

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

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

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let ReactFeatureFlags;
let ReactDOM;
let useKeyboard;

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

function initializeModules(hasPointerEvents) {
jest.resetModules();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

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

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
buttonsType,
createEventTarget,
describeWithPointerEvent,
resetActivePointers,
setPointerEvent,
} from '../testing-library';
} from '../event-testing-library';

let React;
let ReactFeatureFlags;
Expand Down Expand Up @@ -47,6 +48,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
ReactDOM.render(null, container);
document.body.removeChild(container);
container = null;
resetActivePointers();
});

describe('disabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
buttonType,
buttonsType,
createEventTarget,
resetActivePointers,
setPointerEvent,
} from '../testing-library';
} from '../event-testing-library';

let React;
let ReactFeatureFlags;
Expand Down Expand Up @@ -59,6 +60,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
ReactDOM.render(null, container);
document.body.removeChild(container);
container = null;
resetActivePointers();
});

describe('disabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

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

let React;
let ReactFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
describeWithPointerEvent,
setPointerEvent,
testWithPointerType,
} from '../testing-library';
resetActivePointers,
} from '../event-testing-library';

let React;
let ReactFeatureFlags;
Expand Down Expand Up @@ -82,6 +83,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
ReactDOM.render(null, container);
document.body.removeChild(container);
container = null;
resetActivePointers();
});

test('supports repeated use', () => {
Expand Down Expand Up @@ -295,12 +297,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
const buttons = buttonsType.primary;
target.pointerdown({button, buttons, pointerId: 1, pointerType});
expect(onTapStart).toHaveBeenCalledTimes(1);
if (hasPointerEvents) {
target.pointerdown({button, buttons, pointerId: 2, pointerType});
} else {
// TouchEvents
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
}
target.pointerdown({button, buttons, pointerId: 2, pointerType});
expect(onTapStart).toHaveBeenCalledTimes(1);
});

Expand All @@ -313,28 +310,28 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
buttons: buttonsType.secondary,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// middle-click
target.pointerdown({
button: buttonType.auxiliary,
buttons: buttonsType.auxiliary,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// virtual middle-click with misleading 'buttons' value
target.pointerdown({
button: buttonType.auxiliary,
buttons: 0,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// pen eraser
target.pointerdown({
button: buttonType.eraser,
buttons: buttonsType.eraser,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
}
// alt-click
target.pointerdown({
Expand All @@ -343,31 +340,31 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
altKey: true,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// ctrl-click
target.pointerdown({
button: buttonType.primary,
buttons: buttonsType.primary,
ctrlKey: true,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// meta-click
target.pointerdown({
button: buttonType.primary,
buttons: buttonsType.primary,
metaKey: true,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});
// shift-click
target.pointerdown({
button: buttonType.primary,
buttons: buttonsType.primary,
shiftKey: true,
pointerType,
});
target.pointerup();
target.pointerup({pointerType});

expect(onTapStart).toHaveBeenCalledTimes(0);
});
Expand Down Expand Up @@ -565,8 +562,10 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
testWithPointerType('requires activation', pointerType => {
const target = createEventTarget(ref.current);
target.setBoundingClientRect(rect);
target.pointerhover({pointerType, ...coordinates});
target.pointermove({pointerType, ...coordinates});
if (pointerType !== 'touch') {
target.pointerhover({pointerType, ...coordinates});
target.pointermove({pointerType, ...coordinates});
}
expect(onTapUpdate).not.toBeCalled();
});

Expand Down Expand Up @@ -771,12 +770,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
const button = buttonType.primary;
const buttons = buttonsType.primary;
target.pointerdown({button, buttons, pointerId: 1, pointerType});
if (hasPointerEvents) {
target.pointerdown({button, buttons, pointerId: 2, pointerType});
} else {
// TouchEvents
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
}
target.pointerdown({button, buttons, pointerId: 2, pointerType});
expect(onTapCancel).toHaveBeenCalledTimes(1);
});

Expand Down
Loading

0 comments on commit a5e951d

Please sign in to comment.