Skip to content

Commit 4caa4a7

Browse files
committed
refactor: improve dispatch event functions
1 parent 491cf79 commit 4caa4a7

File tree

3 files changed

+58
-30
lines changed

3 files changed

+58
-30
lines changed

src/fireEvent.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import { ReactTestInstance } from 'react-test-renderer';
22
import act from './act';
33
import { getHostParent, isHostElement } from './helpers/component-tree';
4-
import { getHostComponentNames } from './helpers/host-component-names';
4+
import { isHostTextInput } from './helpers/host-component-names';
55

66
type EventHandler = (...args: unknown[]) => unknown;
77

8-
const isHostTextInput = (element?: ReactTestInstance) => {
9-
return element?.type === getHostComponentNames().textInput;
10-
};
11-
128
export function isTouchResponder(element: ReactTestInstance) {
139
if (!isHostElement(element)) {
1410
return false;

src/helpers/host-component-names.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ function getByTestId(instance: ReactTestInstance, testID: string) {
6565

6666
return nodes[0];
6767
}
68+
69+
export function isHostTextInput(element?: ReactTestInstance) {
70+
return element?.type === getHostComponentNames().textInput;
71+
}

src/user-event/utils/dispatch-event.ts

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ReactTestInstance } from 'react-test-renderer';
22
import act from '../../act';
3-
import { isEventEnabled, isTouchResponder } from '../../fireEvent';
43
import { flushMicroTasks } from '../../flushMicroTasks';
54
import { getHostParent } from '../../helpers/component-tree';
5+
import { isHostTextInput } from '../../helpers/host-component-names';
66

77
type EventHandler = (event: unknown) => void;
88

@@ -42,7 +42,7 @@ export function dispatchOwnHostEvent(
4242
eventName: string,
4343
event: unknown
4444
) {
45-
const handler = getEnabledEventHandler(element, eventName);
45+
const handler = getEventHandler(element, eventName);
4646
if (!handler) {
4747
return;
4848
}
@@ -53,45 +53,73 @@ export function dispatchOwnHostEvent(
5353
});
5454
}
5555

56+
/**
57+
* Looks up for event handler in the element and its ancestors.
58+
*/
5659
function findEnabledEventHandler(
5760
element: ReactTestInstance,
5861
eventName: string
5962
): EventHandler | null {
60-
const handler = getEnabledEventHandler(element, eventName);
61-
if (handler) {
62-
return handler;
63-
}
64-
65-
const parent = getHostParent(element);
66-
if (!parent) {
67-
return null;
68-
}
63+
let current: ReactTestInstance | null = element;
64+
while (current != null) {
65+
const handler = getEventHandler(current, eventName);
66+
if (handler) {
67+
return handler;
68+
}
6969

70-
return findEnabledEventHandler(parent, eventName);
71-
}
72-
73-
function getEnabledEventHandler(
74-
element: ReactTestInstance,
75-
eventName: string
76-
): EventHandler | null {
77-
const touchResponder = isTouchResponder(element) ? element : undefined;
78-
const handler = getEventHandler(element, eventName);
79-
if (handler && isEventEnabled(element, eventName, touchResponder)) {
80-
return handler;
70+
current = getHostParent(current);
8171
}
8272

8373
return null;
8474
}
8575

8676
function getEventHandler(element: ReactTestInstance, eventName: string) {
8777
const eventHandlerName = getEventHandlerName(eventName);
88-
if (typeof element.props[eventHandlerName] === 'function') {
89-
return element.props[eventHandlerName];
78+
if (typeof element.props[eventHandlerName] !== 'function') {
79+
return null;
80+
}
81+
82+
if (!isEventEnabled(element)) {
83+
return null;
9084
}
9185

92-
return undefined;
86+
return element.props[eventHandlerName];
9387
}
9488

9589
function getEventHandlerName(eventName: string) {
9690
return `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
9791
}
92+
93+
function isEventEnabled(element: ReactTestInstance) {
94+
if (isHostTextInput(element)) {
95+
return element?.props.editable !== false;
96+
}
97+
98+
if (!isPointerEventEnabled(element)) {
99+
return false;
100+
}
101+
102+
const touchStart = element?.props.onStartShouldSetResponder?.();
103+
return touchStart !== false;
104+
}
105+
106+
export function isPointerEventEnabled(
107+
element: ReactTestInstance,
108+
isParent?: boolean
109+
): boolean {
110+
const pointerEvents = element.props.pointerEvents;
111+
if (pointerEvents === 'none') {
112+
return false;
113+
}
114+
115+
if (isParent ? pointerEvents === 'box-only' : pointerEvents === 'box-none') {
116+
return false;
117+
}
118+
119+
const parent = getHostParent(element);
120+
if (!parent) {
121+
return true;
122+
}
123+
124+
return isPointerEventEnabled(parent, true);
125+
}

0 commit comments

Comments
 (0)