diff --git a/packages/react-events/src/dom/Press.js b/packages/react-events/src/dom/Press.js index 40251331f94b..f526497097f4 100644 --- a/packages/react-events/src/dom/Press.js +++ b/packages/react-events/src/dom/Press.js @@ -520,6 +520,7 @@ const pressResponderImpl = { const isPressed = state.isPressed; handleStopPropagation(props, context, nativeEvent); + switch (type) { // START case 'pointerdown': @@ -632,6 +633,7 @@ const pressResponderImpl = { const previousPointerType = state.pointerType; handleStopPropagation(props, context, nativeEvent); + switch (type) { // MOVE case 'pointermove': diff --git a/packages/react-events/src/dom/Scroll.js b/packages/react-events/src/dom/Scroll.js index 5fa1e34a8e5e..44b782b977c7 100644 --- a/packages/react-events/src/dom/Scroll.js +++ b/packages/react-events/src/dom/Scroll.js @@ -62,14 +62,16 @@ type ScrollEvent = {| y: null | number, |}; -const targetEventTypes = [ - 'scroll', - 'pointerdown', - 'touchstart', - 'keyup', - 'wheel', -]; -const rootEventTypes = ['touchcancel', 'touchend']; +const hasPointerEvents = + typeof window !== 'undefined' && window.PointerEvent !== undefined; + +const targetEventTypes = hasPointerEvents + ? ['scroll', 'pointerdown', 'keyup', 'wheel'] + : ['scroll', 'mousedown', 'touchstart', 'keyup', 'wheel']; + +const rootEventTypes = hasPointerEvents + ? ['pointercancel', 'pointerup'] + : ['touchcancel', 'touchend']; function isFunction(obj): boolean { return typeof obj === 'function'; @@ -237,17 +239,23 @@ const scrollResponderImpl = { state.pointerType = pointerType; break; } + case 'mousedown': case 'wheel': { state.pointerType = 'mouse'; break; } case 'pointerdown': { state.pointerType = pointerType; + if (pointerType === 'touch' && !state.isTouching) { + state.isTouching = true; + context.addRootEventTypes(rootEventTypes); + } break; } case 'touchstart': { if (!state.isTouching) { state.isTouching = true; + state.pointerType = 'touch'; context.addRootEventTypes(rootEventTypes); } } @@ -262,6 +270,8 @@ const scrollResponderImpl = { const {type} = event; switch (type) { + case 'pointercancel': + case 'pointerup': case 'touchcancel': case 'touchend': { if (state.isTouching) { diff --git a/packages/react-events/src/dom/__tests__/ContextMenu-test.internal.js b/packages/react-events/src/dom/__tests__/ContextMenu-test.internal.js index bf2fb0f3e3a7..b25cbf29fcbd 100644 --- a/packages/react-events/src/dom/__tests__/ContextMenu-test.internal.js +++ b/packages/react-events/src/dom/__tests__/ContextMenu-test.internal.js @@ -9,13 +9,7 @@ 'use strict'; -import { - dispatchLongPressContextMenu, - dispatchRightClickContextMenu, - dispatchModifiedClickContextMenu, - platform, - setPointerEvent, -} from '../test-utils'; +import {createEventTarget, platform, setPointerEvent} from '../testing-library'; let React; let ReactFeatureFlags; @@ -62,7 +56,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchRightClickContextMenu(ref.current, {preventDefault}); + const target = createEventTarget(ref.current); + target.contextmenu({preventDefault}); expect(preventDefault).toHaveBeenCalledTimes(1); expect(onContextMenu).toHaveBeenCalledTimes(1); expect(onContextMenu).toHaveBeenCalledWith( @@ -80,7 +75,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchLongPressContextMenu(ref.current, {preventDefault}); + const target = createEventTarget(ref.current); + target.contextmenu({preventDefault}, {pointerType: 'touch'}); expect(preventDefault).toHaveBeenCalledTimes(1); expect(onContextMenu).toHaveBeenCalledTimes(1); expect(onContextMenu).toHaveBeenCalledWith( @@ -100,7 +96,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchRightClickContextMenu(ref.current); + const target = createEventTarget(ref.current); + target.contextmenu(); expect(onContextMenu).toHaveBeenCalledTimes(0); }); @@ -117,7 +114,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchRightClickContextMenu(ref.current, {preventDefault}); + const target = createEventTarget(ref.current); + target.contextmenu({preventDefault}); expect(preventDefault).toHaveBeenCalledTimes(0); expect(onContextMenu).toHaveBeenCalledTimes(1); }); @@ -142,7 +140,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchModifiedClickContextMenu(ref.current); + const target = createEventTarget(ref.current); + target.contextmenu({}, {modified: true}); expect(onContextMenu).toHaveBeenCalledTimes(1); expect(onContextMenu).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'mouse', type: 'contextmenu'}), @@ -169,7 +168,8 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => { }; ReactDOM.render(, container); - dispatchModifiedClickContextMenu(ref.current); + const target = createEventTarget(ref.current); + target.contextmenu({}, {modified: true}); expect(onContextMenu).toHaveBeenCalledTimes(0); }); }); diff --git a/packages/react-events/src/dom/__tests__/Focus-test.internal.js b/packages/react-events/src/dom/__tests__/Focus-test.internal.js index 316bc9f19dcd..12700ce55cc3 100644 --- a/packages/react-events/src/dom/__tests__/Focus-test.internal.js +++ b/packages/react-events/src/dom/__tests__/Focus-test.internal.js @@ -9,15 +9,7 @@ 'use strict'; -import { - blur, - focus, - keydown, - setPointerEvent, - platform, - dispatchPointerDown, - dispatchPointerUp, -} from '../test-utils'; +import {createEventTarget, setPointerEvent, platform} from '../testing-library'; let React; let ReactFeatureFlags; @@ -73,9 +65,9 @@ describe.each(table)('Focus responder', hasPointerEvents => { }); it('does not call callbacks', () => { - const dispatch = arg => ref.current.dispatchEvent(arg); - dispatch(focus()); - dispatch(blur()); + const target = createEventTarget(ref.current); + target.focus(); + target.blur(); expect(onFocus).not.toBeCalled(); expect(onBlur).not.toBeCalled(); }); @@ -97,9 +89,9 @@ describe.each(table)('Focus responder', hasPointerEvents => { }); it('is called after "blur" event', () => { - const dispatch = arg => ref.current.dispatchEvent(arg); - dispatch(focus()); - dispatch(blur()); + const target = createEventTarget(ref.current); + target.focus(); + target.blur(); expect(onBlur).toHaveBeenCalledTimes(1); }); }); @@ -127,19 +119,21 @@ describe.each(table)('Focus responder', hasPointerEvents => { beforeEach(componentInit); it('is called after "focus" event', () => { - ref.current.dispatchEvent(focus()); + const target = createEventTarget(ref.current); + target.focus(); expect(onFocus).toHaveBeenCalledTimes(1); }); it('is not called if descendants of target receive focus', () => { - innerRef.current.dispatchEvent(focus()); + const target = createEventTarget(innerRef.current); + target.focus(); expect(onFocus).not.toBeCalled(); }); it('is called with the correct pointerType: mouse', () => { - const target = ref.current; - dispatchPointerDown(target, {pointerType: 'mouse'}); - dispatchPointerUp(target, {pointerType: 'mouse'}); + const target = createEventTarget(ref.current); + target.pointerdown(); + target.pointerup(); expect(onFocus).toHaveBeenCalledTimes(1); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'mouse'}), @@ -147,9 +141,10 @@ describe.each(table)('Focus responder', hasPointerEvents => { }); it('is called with the correct pointerType: touch', () => { - const target = ref.current; - dispatchPointerDown(target, {pointerType: 'touch'}); - dispatchPointerUp(target, {pointerType: 'touch'}); + const target = createEventTarget(ref.current); + const pointerType = 'touch'; + target.pointerdown({pointerType}); + target.pointerup({pointerType}); expect(onFocus).toHaveBeenCalledTimes(1); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'touch'}), @@ -158,9 +153,10 @@ describe.each(table)('Focus responder', hasPointerEvents => { if (hasPointerEvents) { it('is called with the correct pointerType: pen', () => { - const target = ref.current; - dispatchPointerDown(target, {pointerType: 'pen'}); - dispatchPointerUp(target, {pointerType: 'pen'}); + const target = createEventTarget(ref.current); + const pointerType = 'pen'; + target.pointerdown({pointerType}); + target.pointerup({pointerType}); expect(onFocus).toHaveBeenCalledTimes(1); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'pen'}), @@ -169,10 +165,9 @@ describe.each(table)('Focus responder', hasPointerEvents => { } it('is called with the correct pointerType using a keyboard', () => { - const target = ref.current; - // Keyboard tab - target.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(focus()); + const target = createEventTarget(ref.current); + target.keydown({key: 'Tab'}); + target.focus(); expect(onFocus).toHaveBeenCalledTimes(1); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'keyboard'}), @@ -184,10 +179,11 @@ describe.each(table)('Focus responder', hasPointerEvents => { jest.resetModules(); initializeModules(); componentInit(); - const target = ref.current; - target.dispatchEvent(keydown({key: 'Tab', altKey: true})); - target.dispatchEvent(focus()); + const target = createEventTarget(ref.current); + target.keydown({key: 'Tab', altKey: true}); + target.focus(); + expect(onFocus).toHaveBeenCalledTimes(1); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({ @@ -220,20 +216,20 @@ describe.each(table)('Focus responder', hasPointerEvents => { }); it('is called after "blur" and "focus" events', () => { - const target = ref.current; - target.dispatchEvent(focus()); + const target = createEventTarget(ref.current); + target.focus(); expect(onFocusChange).toHaveBeenCalledTimes(1); expect(onFocusChange).toHaveBeenCalledWith(true); - target.dispatchEvent(blur()); + target.blur(); expect(onFocusChange).toHaveBeenCalledTimes(2); expect(onFocusChange).toHaveBeenCalledWith(false); }); it('is not called after "blur" and "focus" events on descendants', () => { - const target = innerRef.current; - target.dispatchEvent(focus()); + const target = createEventTarget(innerRef.current); + target.focus(); expect(onFocusChange).toHaveBeenCalledTimes(0); - target.dispatchEvent(blur()); + target.blur(); expect(onFocusChange).toHaveBeenCalledTimes(0); }); }); @@ -259,48 +255,52 @@ describe.each(table)('Focus responder', hasPointerEvents => { }); it('is called after "focus" and "blur" if keyboard navigation is active', () => { - const target = ref.current; + const target = createEventTarget(ref.current); + const containerTarget = createEventTarget(container); // use keyboard first - container.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(focus()); + containerTarget.keydown({key: 'Tab'}); + target.focus(); expect(onFocusVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusVisibleChange).toHaveBeenCalledWith(true); - target.dispatchEvent(blur({relatedTarget: container})); + target.blur({relatedTarget: container}); expect(onFocusVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusVisibleChange).toHaveBeenCalledWith(false); }); it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => { - const target = ref.current; + const target = createEventTarget(ref.current); + const containerTarget = createEventTarget(container); // use keyboard first - container.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(focus()); + containerTarget.keydown({key: 'Tab'}); + target.focus(); expect(onFocusVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusVisibleChange).toHaveBeenCalledWith(true); // then use pointer on the target, focus should no longer be visible - dispatchPointerDown(target); + target.pointerdown(); expect(onFocusVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusVisibleChange).toHaveBeenCalledWith(false); // onFocusVisibleChange should not be called again - target.dispatchEvent(blur({relatedTarget: container})); + target.blur({relatedTarget: container}); expect(onFocusVisibleChange).toHaveBeenCalledTimes(2); }); it('is not called after "focus" and "blur" events without keyboard', () => { - const target = ref.current; - dispatchPointerDown(target); - dispatchPointerUp(target); - dispatchPointerDown(container); - target.dispatchEvent(blur({relatedTarget: container})); + const target = createEventTarget(ref.current); + const containerTarget = createEventTarget(container); + target.pointerdown(); + target.pointerup(); + containerTarget.pointerdown(); + target.blur({relatedTarget: container}); expect(onFocusVisibleChange).toHaveBeenCalledTimes(0); }); it('is not called after "blur" and "focus" events on descendants', () => { - const target = innerRef.current; - container.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(focus()); + const innerTarget = createEventTarget(innerRef.current); + const containerTarget = createEventTarget(container); + containerTarget.keydown({key: 'Tab'}); + innerTarget.focus(); expect(onFocusVisibleChange).toHaveBeenCalledTimes(0); - target.dispatchEvent(blur({relatedTarget: container})); + innerTarget.blur({relatedTarget: container}); expect(onFocusVisibleChange).toHaveBeenCalledTimes(0); }); }); @@ -338,10 +338,13 @@ describe.each(table)('Focus responder', hasPointerEvents => { ReactDOM.render(, container); - outerRef.current.dispatchEvent(focus()); - outerRef.current.dispatchEvent(blur()); - innerRef.current.dispatchEvent(focus()); - innerRef.current.dispatchEvent(blur()); + const innerTarget = createEventTarget(innerRef.current); + const outerTarget = createEventTarget(outerRef.current); + + outerTarget.focus(); + outerTarget.blur(); + innerTarget.focus(); + innerTarget.blur(); expect(events).toEqual([ 'outer: onFocus', 'outer: onFocusChange', diff --git a/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js b/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js index ff54b6f3838e..f6f5ffecb752 100644 --- a/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js +++ b/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js @@ -9,14 +9,7 @@ 'use strict'; -import { - blur, - focus, - keydown, - setPointerEvent, - dispatchPointerDown, - dispatchPointerUp, -} from '../test-utils'; +import {createEventTarget, setPointerEvent} from '../testing-library'; let React; let ReactFeatureFlags; @@ -73,9 +66,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => { }); it('prevents custom events being dispatched', () => { - const target = ref.current; - target.dispatchEvent(focus()); - target.dispatchEvent(blur()); + const target = createEventTarget(ref.current); + target.focus(); + target.blur(); expect(onFocusWithinChange).not.toBeCalled(); expect(onFocusWithinVisibleChange).not.toBeCalled(); }); @@ -104,42 +97,46 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => { }); it('is called after "blur" and "focus" events on focus target', () => { - const target = ref.current; - target.dispatchEvent(focus()); + const target = createEventTarget(ref.current); + target.focus(); expect(onFocusWithinChange).toHaveBeenCalledTimes(1); expect(onFocusWithinChange).toHaveBeenCalledWith(true); - target.dispatchEvent(blur({relatedTarget: container})); + target.blur({relatedTarget: container}); expect(onFocusWithinChange).toHaveBeenCalledTimes(2); expect(onFocusWithinChange).toHaveBeenCalledWith(false); }); it('is called after "blur" and "focus" events on descendants', () => { - const target = innerRef.current; - target.dispatchEvent(focus()); + const target = createEventTarget(innerRef.current); + target.focus(); expect(onFocusWithinChange).toHaveBeenCalledTimes(1); expect(onFocusWithinChange).toHaveBeenCalledWith(true); - target.dispatchEvent(blur({relatedTarget: container})); + target.blur({relatedTarget: container}); expect(onFocusWithinChange).toHaveBeenCalledTimes(2); expect(onFocusWithinChange).toHaveBeenCalledWith(false); }); it('is only called once when focus moves within and outside the subtree', () => { - const target = ref.current; - const innerTarget1 = innerRef.current; - const innerTarget2 = innerRef2.current; + const node = ref.current; + const innerNode1 = innerRef.current; + const innerNode2 = innerRef.current; + const target = createEventTarget(node); + const innerTarget1 = createEventTarget(innerNode1); + const innerTarget2 = createEventTarget(innerNode2); + // focus shifts into subtree - innerTarget1.dispatchEvent(focus()); + innerTarget1.focus(); expect(onFocusWithinChange).toHaveBeenCalledTimes(1); expect(onFocusWithinChange).toHaveBeenCalledWith(true); // focus moves around subtree - innerTarget1.dispatchEvent(blur({relatedTarget: innerTarget2})); - innerTarget2.dispatchEvent(focus()); - innerTarget2.dispatchEvent(blur({relatedTarget: target})); - target.dispatchEvent(focus()); - target.dispatchEvent(blur({relatedTarget: innerTarget1})); + innerTarget1.blur({relatedTarget: innerNode2}); + innerTarget2.focus(); + innerTarget2.blur({relatedTarget: node}); + target.focus(); + target.blur({relatedTarget: innerNode1}); expect(onFocusWithinChange).toHaveBeenCalledTimes(1); // focus shifts outside subtree - innerTarget1.dispatchEvent(blur({relatedTarget: container})); + innerTarget1.blur({relatedTarget: container}); expect(onFocusWithinChange).toHaveBeenCalledTimes(2); expect(onFocusWithinChange).toHaveBeenCalledWith(false); }); @@ -168,87 +165,96 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => { }); it('is called after "focus" and "blur" on focus target if keyboard was used', () => { - const target = ref.current; + const target = createEventTarget(ref.current); + const containerTarget = createEventTarget(container); // use keyboard first - container.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(focus()); + containerTarget.keydown({key: 'Tab'}); + target.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true); - target.dispatchEvent(blur({relatedTarget: container})); + target.blur({relatedTarget: container}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false); }); it('is called after "focus" and "blur" on descendants if keyboard was used', () => { - const innerTarget = innerRef.current; + const innerTarget = createEventTarget(innerRef.current); + const containerTarget = createEventTarget(container); // use keyboard first - container.dispatchEvent(keydown({key: 'Tab'})); - innerTarget.dispatchEvent(focus()); + containerTarget.keydown({key: 'Tab'}); + innerTarget.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true); - innerTarget.dispatchEvent(blur({relatedTarget: container})); + innerTarget.blur({relatedTarget: container}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false); }); it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => { - const target = ref.current; - const innerTarget1 = innerRef.current; - const innerTarget2 = innerRef2.current; + const node = ref.current; + const innerNode1 = innerRef.current; + const innerNode2 = innerRef2.current; + + const target = createEventTarget(node); + const innerTarget1 = createEventTarget(innerNode1); + const innerTarget2 = createEventTarget(innerNode2); // use keyboard first - target.dispatchEvent(focus()); - target.dispatchEvent(keydown({key: 'Tab'})); - target.dispatchEvent(blur({relatedTarget: innerTarget1})); - innerTarget1.dispatchEvent(focus()); + target.focus(); + target.keydown({key: 'Tab'}); + target.blur({relatedTarget: innerNode1}); + innerTarget1.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true); // then use pointer on the next target, focus should no longer be visible - dispatchPointerDown(innerTarget2); - innerTarget1.dispatchEvent(blur({relatedTarget: innerTarget2})); - innerTarget2.dispatchEvent(focus()); + innerTarget2.pointerdown(); + innerTarget1.blur({relatedTarget: innerNode2}); + innerTarget2.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false); // then use keyboard again - innerTarget2.dispatchEvent(keydown({key: 'Tab', shiftKey: true})); - innerTarget2.dispatchEvent(blur({relatedTarget: innerTarget1})); - innerTarget1.dispatchEvent(focus()); + innerTarget2.keydown({key: 'Tab', shiftKey: true}); + innerTarget2.blur({relatedTarget: innerNode1}); + innerTarget1.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(3); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true); // then use pointer on the target, focus should no longer be visible - dispatchPointerDown(innerTarget1); + innerTarget1.pointerdown(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false); // onFocusVisibleChange should not be called again - innerTarget1.dispatchEvent(blur({relatedTarget: container})); + innerTarget1.blur({relatedTarget: container}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4); }); it('is not called after "focus" and "blur" events without keyboard', () => { - const innerTarget = innerRef.current; - dispatchPointerDown(innerTarget); - dispatchPointerUp(innerTarget); - innerTarget.dispatchEvent(blur({relatedTarget: container})); + const innerTarget = createEventTarget(innerRef.current); + innerTarget.pointerdown(); + innerTarget.pointerup(); + innerTarget.blur({relatedTarget: container}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0); }); it('is only called once when focus moves within and outside the subtree', () => { - const target = ref.current; - const innerTarget1 = innerRef.current; - const innerTarget2 = innerRef2.current; + const node = ref.current; + const innerNode1 = innerRef.current; + const innerNode2 = innerRef2.current; + const target = createEventTarget(node); + const innerTarget1 = createEventTarget(innerNode1); + const innerTarget2 = createEventTarget(innerNode2); // focus shifts into subtree - innerTarget1.dispatchEvent(focus()); + innerTarget1.focus(); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true); // focus moves around subtree - innerTarget1.dispatchEvent(blur({relatedTarget: innerTarget2})); - innerTarget2.dispatchEvent(focus()); - innerTarget2.dispatchEvent(blur({relatedTarget: target})); - target.dispatchEvent(focus()); - target.dispatchEvent(blur({relatedTarget: innerTarget1})); + innerTarget1.blur({relatedTarget: innerNode2}); + innerTarget2.focus(); + innerTarget2.blur({relatedTarget: node}); + target.focus(); + target.blur({relatedTarget: innerNode1}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1); // focus shifts outside subtree - innerTarget1.dispatchEvent(blur({relatedTarget: container})); + innerTarget1.blur({relatedTarget: container}); expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2); expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false); }); diff --git a/packages/react-events/src/dom/__tests__/Hover-test.internal.js b/packages/react-events/src/dom/__tests__/Hover-test.internal.js index 2198e7455115..019a2d2b0678 100644 --- a/packages/react-events/src/dom/__tests__/Hover-test.internal.js +++ b/packages/react-events/src/dom/__tests__/Hover-test.internal.js @@ -9,14 +9,7 @@ 'use strict'; -import { - dispatchPointerCancel, - dispatchPointerHoverEnter, - dispatchPointerHoverExit, - dispatchPointerHoverMove, - dispatchTouchTap, - setPointerEvent, -} from '../test-utils'; +import {createEventTarget, setPointerEvent} from '../testing-library'; let React; let ReactFeatureFlags; @@ -77,9 +70,9 @@ describe.each(table)('Hover responder', hasPointerEvents => { }); it('does not call callbacks', () => { - const target = ref.current; - dispatchPointerHoverEnter(target); - dispatchPointerHoverExit(target); + const target = createEventTarget(ref.current); + target.pointerenter(); + target.pointerexit(); expect(onHoverChange).not.toBeCalled(); expect(onHoverStart).not.toBeCalled(); expect(onHoverMove).not.toBeCalled(); @@ -103,21 +96,23 @@ describe.each(table)('Hover responder', hasPointerEvents => { }); it('is called for mouse pointers', () => { - const target = ref.current; - dispatchPointerHoverEnter(target); + const target = createEventTarget(ref.current); + target.pointerenter(); expect(onHoverStart).toHaveBeenCalledTimes(1); }); it('is not called for touch pointers', () => { - const target = ref.current; - dispatchTouchTap(target); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType: 'touch'}); + target.pointerup({pointerType: 'touch'}); expect(onHoverStart).not.toBeCalled(); }); it('is called if a mouse pointer is used after a touch pointer', () => { - const target = ref.current; - dispatchTouchTap(target); - dispatchPointerHoverEnter(target); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType: 'touch'}); + target.pointerup({pointerType: 'touch'}); + target.pointerenter(); expect(onHoverStart).toHaveBeenCalledTimes(1); }); }); @@ -138,18 +133,19 @@ describe.each(table)('Hover responder', hasPointerEvents => { }); it('is called for mouse pointers', () => { - const target = ref.current; - dispatchPointerHoverEnter(target); + const target = createEventTarget(ref.current); + target.pointerenter(); expect(onHoverChange).toHaveBeenCalledTimes(1); expect(onHoverChange).toHaveBeenCalledWith(true); - dispatchPointerHoverExit(target); + target.pointerexit(); expect(onHoverChange).toHaveBeenCalledTimes(2); expect(onHoverChange).toHaveBeenCalledWith(false); }); it('is not called for touch pointers', () => { - const target = ref.current; - dispatchTouchTap(target); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType: 'touch'}); + target.pointerup({pointerType: 'touch'}); expect(onHoverChange).not.toBeCalled(); }); }); @@ -170,31 +166,32 @@ describe.each(table)('Hover responder', hasPointerEvents => { }); it('is called for mouse pointers', () => { - const target = ref.current; - dispatchPointerHoverEnter(target); - dispatchPointerHoverExit(target); + const target = createEventTarget(ref.current); + target.pointerenter(); + target.pointerexit(); expect(onHoverEnd).toHaveBeenCalledTimes(1); }); if (hasPointerEvents) { it('is called once for cancelled mouse pointers', () => { - const target = ref.current; - dispatchPointerHoverEnter(target); - dispatchPointerCancel(target); + const target = createEventTarget(ref.current); + target.pointerenter(); + target.pointercancel(); expect(onHoverEnd).toHaveBeenCalledTimes(1); // only called once if cancel follows exit onHoverEnd.mockReset(); - dispatchPointerHoverEnter(target); - dispatchPointerHoverExit(target); - dispatchPointerCancel(target); + target.pointerenter(); + target.pointerexit(); + target.pointercancel(); expect(onHoverEnd).toHaveBeenCalledTimes(1); }); } it('is not called for touch pointers', () => { - const target = ref.current; - dispatchTouchTap(target); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType: 'touch'}); + target.pointerup({pointerType: 'touch'}); expect(onHoverEnd).not.toBeCalled(); }); }); @@ -211,10 +208,10 @@ describe.each(table)('Hover responder', hasPointerEvents => { }; ReactDOM.render(, container); - const target = ref.current; - dispatchPointerHoverEnter(target); - dispatchPointerHoverMove(target, {x: 0, y: 0}); - dispatchPointerHoverMove(target, {x: 1, y: 1}); + const target = createEventTarget(ref.current); + target.pointerenter(); + target.pointerhover({x: 0, y: 0}); + target.pointerhover({x: 1, y: 1}); expect(onHoverMove).toHaveBeenCalledTimes(2); expect(onHoverMove).toHaveBeenCalledWith( expect.objectContaining({type: 'hovermove'}), @@ -254,15 +251,17 @@ describe.each(table)('Hover responder', hasPointerEvents => { }; ReactDOM.render(, container); - const innerTarget = innerRef.current; - const outerTarget = outerRef.current; + const innerNode = innerRef.current; + const outerNode = outerRef.current; + const innerTarget = createEventTarget(innerNode); + const outerTarget = createEventTarget(outerNode); - dispatchPointerHoverEnter(outerTarget, {relatedTarget: container}); - dispatchPointerHoverExit(outerTarget, {relatedTarget: innerTarget}); - dispatchPointerHoverEnter(innerTarget, {relatedTarget: outerTarget}); - dispatchPointerHoverExit(innerTarget, {relatedTarget: outerTarget}); - dispatchPointerHoverEnter(outerTarget, {relatedTarget: innerTarget}); - dispatchPointerHoverExit(outerTarget, {relatedTarget: container}); + outerTarget.pointerenter({relatedTarget: container}); + outerTarget.pointerexit({relatedTarget: innerNode}); + innerTarget.pointerenter({relatedTarget: outerNode}); + innerTarget.pointerexit({relatedTarget: outerNode}); + outerTarget.pointerenter({relatedTarget: innerNode}); + outerTarget.pointerexit({relatedTarget: container}); expect(events).toEqual([ 'outer: onHoverStart', @@ -315,12 +314,13 @@ describe.each(table)('Hover responder', hasPointerEvents => { }; ReactDOM.render(, container); - const target = ref.current; + const node = ref.current; + const target = createEventTarget(node); - dispatchPointerHoverEnter(target, {x: 10, y: 10}); - dispatchPointerHoverMove(target, {x: 10, y: 10}); - dispatchPointerHoverMove(target, {x: 20, y: 20}); - dispatchPointerHoverExit(target, {x: 20, y: 20}); + target.pointerenter({x: 10, y: 10}); + target.pointerhover({x: 10, y: 10}); + target.pointerhover({x: 20, y: 20}); + target.pointerexit({x: 20, y: 20}); expect(eventLog).toEqual([ { @@ -330,7 +330,7 @@ describe.each(table)('Hover responder', hasPointerEvents => { pageY: 10, clientX: 10, clientY: 10, - target, + target: node, timeStamp: timeStamps[0], type: 'hoverstart', pointerType: 'mouse', @@ -342,7 +342,7 @@ describe.each(table)('Hover responder', hasPointerEvents => { pageY: 10, clientX: 10, clientY: 10, - target, + target: node, timeStamp: timeStamps[1], type: 'hovermove', pointerType: 'mouse', @@ -354,7 +354,7 @@ describe.each(table)('Hover responder', hasPointerEvents => { pageY: 20, clientX: 20, clientY: 20, - target, + target: node, timeStamp: timeStamps[2], type: 'hovermove', pointerType: 'mouse', @@ -366,7 +366,7 @@ describe.each(table)('Hover responder', hasPointerEvents => { pageY: 20, clientX: 20, clientY: 20, - target, + target: node, timeStamp: timeStamps[3], type: 'hoverend', pointerType: 'mouse', diff --git a/packages/react-events/src/dom/__tests__/Keyboard-test.internal.js b/packages/react-events/src/dom/__tests__/Keyboard-test.internal.js index f3a655f79039..613d1e6cace3 100644 --- a/packages/react-events/src/dom/__tests__/Keyboard-test.internal.js +++ b/packages/react-events/src/dom/__tests__/Keyboard-test.internal.js @@ -14,7 +14,7 @@ let ReactFeatureFlags; let ReactDOM; let useKeyboardResponder; -import {keydown, keyup} from '../test-utils'; +import {createEventTarget} from '../testing-library'; function initializeModules(hasPointerEvents) { jest.resetModules(); @@ -59,9 +59,9 @@ describe('Keyboard event responder', () => { }); it('prevents custom events being dispatched', () => { - const target = ref.current; - target.dispatchEvent(keydown()); - target.dispatchEvent(keyup()); + const target = createEventTarget(ref.current); + target.keydown(); + target.keyup(); expect(onKeyDown).not.toBeCalled(); expect(onKeyUp).not.toBeCalled(); }); @@ -83,7 +83,8 @@ describe('Keyboard event responder', () => { }); it('is called after "keydown" event', () => { - ref.current.dispatchEvent(keydown({key: 'Q'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Q'}); expect(onKeyDown).toHaveBeenCalledTimes(1); expect(onKeyDown).toHaveBeenCalledWith( expect.objectContaining({key: 'Q', type: 'keydown'}), @@ -109,9 +110,9 @@ describe('Keyboard event responder', () => { }); it('is called after "keydown" event', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Q'})); - target.dispatchEvent(keyup({key: 'Q'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Q'}); + target.keyup({key: 'Q'}); expect(onKeyDown).toHaveBeenCalledTimes(1); expect(onKeyDown).toHaveBeenCalledWith( expect.objectContaining({key: 'Q', type: 'keydown'}), diff --git a/packages/react-events/src/dom/__tests__/Press-test.internal.js b/packages/react-events/src/dom/__tests__/Press-test.internal.js index a6a42a5d011a..10ddd2af356c 100644 --- a/packages/react-events/src/dom/__tests__/Press-test.internal.js +++ b/packages/react-events/src/dom/__tests__/Press-test.internal.js @@ -9,27 +9,13 @@ 'use strict'; -import { - click, - dispatchPointerCancel, - dispatchPointerDown, - dispatchPointerUp, - dispatchPointerHoverMove, - dispatchPointerMove, - keydown, - keyup, - scroll, - pointerdown, - pointerup, - setPointerEvent, -} from '../test-utils'; +import {createEventTarget, setPointerEvent} from '../testing-library'; let React; let ReactFeatureFlags; let ReactDOM; let PressResponder; let usePressResponder; -let Scheduler; function initializeModules(hasPointerEvents) { jest.resetModules(); @@ -40,7 +26,6 @@ function initializeModules(hasPointerEvents) { ReactDOM = require('react-dom'); PressResponder = require('react-events/press').PressResponder; usePressResponder = require('react-events/press').usePressResponder; - Scheduler = require('scheduler'); } function removePressMoveStrings(eventString) { @@ -92,9 +77,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('does not call callbacks', () => { - const target = ref.current; - dispatchPointerDown(target); - dispatchPointerUp(target); + const target = createEventTarget(ref.current); + target.pointerdown(); + target.pointerup(); expect(onPressStart).not.toBeCalled(); expect(onPress).not.toBeCalled(); expect(onPressEnd).not.toBeCalled(); @@ -120,7 +105,8 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { it.each(pointerTypesTable)( 'is called after pointer down: %s', pointerType => { - dispatchPointerDown(ref.current, {pointerType}); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType}); expect(onPressStart).toHaveBeenCalledTimes(1); expect(onPressStart).toHaveBeenCalledWith( expect.objectContaining({pointerType, type: 'pressstart'}), @@ -129,7 +115,8 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { ); it('is called after auxillary-button pointer down', () => { - dispatchPointerDown(ref.current, {button: 1, pointerType: 'mouse'}); + const target = createEventTarget(ref.current); + target.pointerdown({button: 1, pointerType: 'mouse'}); expect(onPressStart).toHaveBeenCalledTimes(1); expect(onPressStart).toHaveBeenCalledWith( expect.objectContaining({ @@ -140,39 +127,31 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { ); }); - it('is not called after "pointermove" following auxillary-button press', () => { - const target = ref.current; - target.getBoundingClientRect = () => ({ - top: 0, - left: 0, - bottom: 100, - right: 100, - }); - dispatchPointerDown(target, { - button: 1, - pointerType: 'mouse', - }); - dispatchPointerUp(target, { - button: 1, - pointerType: 'mouse', - }); - dispatchPointerHoverMove(target, {x: 110, y: 110}); - dispatchPointerHoverMove(target, {x: 50, y: 50}); + it('is not called after pointer move following auxillary-button press', () => { + const node = ref.current; + const target = createEventTarget(node); + target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100}); + target.pointerdown({button: 1, pointerType: 'mouse'}); + target.pointerup({button: 1, pointerType: 'mouse'}); + target.pointerhover({x: 110, y: 110}); + target.pointerhover({x: 50, y: 50}); expect(onPressStart).toHaveBeenCalledTimes(1); }); it('ignores any events not caused by primary/auxillary-click or touch/pen contact', () => { - const target = ref.current; - dispatchPointerDown(target, {button: 2}); - dispatchPointerDown(target, {button: 5}); + const target = createEventTarget(ref.current); + target.pointerdown({button: 2}); + target.pointerup({button: 2}); + target.pointerdown({button: 5}); + target.pointerup({button: 5}); expect(onPressStart).toHaveBeenCalledTimes(0); }); it('is called once after "keydown" events for Enter', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent(keydown({key: 'Enter'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); + target.keydown({key: 'Enter'}); + target.keydown({key: 'Enter'}); expect(onPressStart).toHaveBeenCalledTimes(1); expect(onPressStart).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'keyboard', type: 'pressstart'}), @@ -180,11 +159,11 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('is called once after "keydown" events for Spacebar', () => { - const target = ref.current; + const target = createEventTarget(ref.current); const preventDefault = jest.fn(); - target.dispatchEvent(keydown({key: ' ', preventDefault})); + target.keydown({key: ' ', preventDefault}); expect(preventDefault).toBeCalled(); - target.dispatchEvent(keydown({key: ' ', preventDefault})); + target.keydown({key: ' ', preventDefault}); expect(onPressStart).toHaveBeenCalledTimes(1); expect(onPressStart).toHaveBeenCalledWith( expect.objectContaining({ @@ -195,7 +174,8 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('is not called after "keydown" for other keys', () => { - ref.current.dispatchEvent(keydown({key: 'a'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'a'}); expect(onPressStart).not.toBeCalled(); }); }); @@ -219,9 +199,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { it.each(pointerTypesTable)( 'is called after pointer up: %s', pointerType => { - const target = ref.current; - dispatchPointerDown(target, {pointerType}); - dispatchPointerUp(target, {pointerType}); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType}); + target.pointerup({pointerType}); expect(onPressEnd).toHaveBeenCalledTimes(1); expect(onPressEnd).toHaveBeenCalledWith( expect.objectContaining({pointerType, type: 'pressend'}), @@ -230,9 +210,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { ); it('is called after auxillary-button pointer up', () => { - const target = ref.current; - dispatchPointerDown(target, {button: 1, pointerType: 'mouse'}); - dispatchPointerUp(target, {button: 1, pointerType: 'mouse'}); + const target = createEventTarget(ref.current); + target.pointerdown({button: 1, pointerType: 'mouse'}); + target.pointerup({button: 1, pointerType: 'mouse'}); expect(onPressEnd).toHaveBeenCalledTimes(1); expect(onPressEnd).toHaveBeenCalledWith( expect.objectContaining({ @@ -244,11 +224,11 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('is called after "keyup" event for Enter', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Enter'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); // click occurs before keyup - target.dispatchEvent(click()); - target.dispatchEvent(keyup({key: 'Enter'})); + target.click(); + target.keyup({key: 'Enter'}); expect(onPressEnd).toHaveBeenCalledTimes(1); expect(onPressEnd).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}), @@ -256,9 +236,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('is called after "keyup" event for Spacebar', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: ' '})); - target.dispatchEvent(keyup({key: ' '})); + const target = createEventTarget(ref.current); + target.keydown({key: ' '}); + target.keyup({key: ' '}); expect(onPressEnd).toHaveBeenCalledTimes(1); expect(onPressEnd).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}), @@ -266,24 +246,22 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { }); it('is not called after "keyup" event for other keys', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent(keyup({key: 'a'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); + target.keyup({key: 'a'}); expect(onPressEnd).not.toBeCalled(); }); it('is called with keyboard modifiers', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent( - keyup({ - key: 'Enter', - metaKey: true, - ctrlKey: true, - altKey: true, - shiftKey: true, - }), - ); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); + target.keyup({ + key: 'Enter', + metaKey: true, + ctrlKey: true, + altKey: true, + shiftKey: true, + }); expect(onPressEnd).toHaveBeenCalledWith( expect.objectContaining({ pointerType: 'keyboard', @@ -316,21 +294,22 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { it.each(pointerTypesTable)( 'is called after pointer down and up: %s', pointerType => { - const target = ref.current; - dispatchPointerDown(target, {pointerType}); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType}); expect(onPressChange).toHaveBeenCalledTimes(1); expect(onPressChange).toHaveBeenCalledWith(true); - dispatchPointerUp(target, {pointerType}); + target.pointerup({pointerType}); expect(onPressChange).toHaveBeenCalledTimes(2); expect(onPressChange).toHaveBeenCalledWith(false); }, ); it('is called after valid "keydown" and "keyup" events', () => { - ref.current.dispatchEvent(keydown({key: 'Enter'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); expect(onPressChange).toHaveBeenCalledTimes(1); expect(onPressChange).toHaveBeenCalledWith(true); - ref.current.dispatchEvent(keyup({key: 'Enter'})); + target.keyup({key: 'Enter'}); expect(onPressChange).toHaveBeenCalledTimes(2); expect(onPressChange).toHaveBeenCalledWith(false); }); @@ -361,9 +340,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { it.each(pointerTypesTable)( 'is called after pointer up: %s', pointerType => { - const target = ref.current; - dispatchPointerDown(target, {pointerType}); - dispatchPointerUp(target, {pointerType, x: 10, y: 10}); + const target = createEventTarget(ref.current); + target.pointerdown({pointerType}); + target.pointerup({pointerType, x: 10, y: 10}); expect(onPress).toHaveBeenCalledTimes(1); expect(onPress).toHaveBeenCalledWith( expect.objectContaining({pointerType, type: 'press'}), @@ -372,16 +351,16 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { ); it('is not called after auxillary-button press', () => { - const target = ref.current; - dispatchPointerDown(target, {button: 1, pointerType: 'mouse'}); - dispatchPointerUp(target, {button: 1, pointerType: 'mouse'}); + const target = createEventTarget(ref.current); + target.pointerdown({button: 1, pointerType: 'mouse'}); + target.pointerup({button: 1, pointerType: 'mouse'}); expect(onPress).not.toHaveBeenCalled(); }); it('is called after valid "keyup" event', () => { - const target = ref.current; - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent(keyup({key: 'Enter'})); + const target = createEventTarget(ref.current); + target.keydown({key: 'Enter'}); + target.keyup({key: 'Enter'}); expect(onPress).toHaveBeenCalledTimes(1); expect(onPress).toHaveBeenCalledWith( expect.objectContaining({pointerType: 'keyboard', type: 'press'}), @@ -391,27 +370,22 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { it('is not called after invalid "keyup" event', () => { const inputRef = React.createRef(); const Component = () => { - const listener = usePressResponder({ - onPress, - }); + const listener = usePressResponder({onPress}); return ; }; ReactDOM.render(, container); - const target = inputRef.current; - target.dispatchEvent(keydown({key: 'Enter'})); - target.dispatchEvent(keyup({key: 'Enter'})); - target.dispatchEvent(keydown({key: ' '})); - target.dispatchEvent(keyup({key: ' '})); + const target = createEventTarget(inputRef.current); + target.keydown({key: 'Enter'}); + target.keyup({key: 'Enter'}); + target.keydown({key: ' '}); + target.keyup({key: ' '}); expect(onPress).not.toBeCalled(); }); it('is called with modifier keys', () => { - const target = ref.current; - dispatchPointerDown(target, {metaKey: true, pointerType: 'mouse'}); - dispatchPointerUp(target, { - metaKey: true, - pointerType: 'mouse', - }); + const target = createEventTarget(ref.current); + target.pointerdown({metaKey: true, pointerType: 'mouse'}); + target.pointerup({metaKey: true, pointerType: 'mouse'}); expect(onPress).toHaveBeenCalledWith( expect.objectContaining({ pointerType: 'mouse', @@ -426,9 +400,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => { const divRef = React.createRef(); const Component = () => { - const listener = usePressResponder({ - onPress, - }); + const listener = usePressResponder({onPress}); return (