diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx
index 184ba6067..faea59fd6 100644
--- a/src/__tests__/fireEvent.test.tsx
+++ b/src/__tests__/fireEvent.test.tsx
@@ -9,6 +9,7 @@ import {
TextInput,
} from 'react-native';
import { render, fireEvent } from '..';
+import { defaultPressEvent } from '../helpers/create-event';
type OnPressComponentProps = {
onPress: () => void;
@@ -104,22 +105,33 @@ describe('fireEvent', () => {
});
});
-test('fireEvent.press', () => {
+test('fireEvent.press with default event', () => {
const onPressMock = jest.fn();
- const text = 'Fireevent press';
- const eventData = {
- nativeEvent: {
- pageX: 20,
- pageY: 30,
- },
- };
- const { getByText } = render(
-
- );
+ const view = render();
- fireEvent.press(getByText(text), eventData);
+ fireEvent.press(view.getByTestId('pressable'));
+ expect(onPressMock).toHaveBeenCalledWith({ nativeEvent: defaultPressEvent });
+});
- expect(onPressMock).toHaveBeenCalledWith(eventData);
+test('fireEvent.press with default event override', () => {
+ const onPressMock = jest.fn();
+ const view = render();
+
+ fireEvent.press(view.getByTestId('pressable'), { pageX: 10, pageY: 20 });
+ expect(onPressMock).toHaveBeenCalledWith({
+ nativeEvent: { ...defaultPressEvent, pageX: 10, pageY: 20 },
+ });
+});
+
+test('fireEvent.press with explicit event', () => {
+ const onPressMock = jest.fn();
+ const view = render();
+
+ const event = {
+ nativeEvent: { pageX: 20, pageY: 30 },
+ };
+ fireEvent.press(view.getByTestId('pressable'), event);
+ expect(onPressMock).toHaveBeenCalledWith(event);
});
test('fireEvent.scroll', () => {
diff --git a/src/fireEvent.ts b/src/fireEvent.ts
index f5ec35f4f..520e9ac36 100644
--- a/src/fireEvent.ts
+++ b/src/fireEvent.ts
@@ -3,6 +3,7 @@ import { TextInput } from 'react-native';
import act from './act';
import { isHostElement } from './helpers/component-tree';
import { filterNodeByType } from './helpers/filterNodeByType';
+import { createEvent } from './helpers/create-event';
type EventHandler = (...args: any) => unknown;
@@ -69,7 +70,6 @@ const isEventEnabled = (
const findEventHandler = (
element: ReactTestInstance,
eventName: string,
- callsite?: any,
nearestTouchResponder?: ReactTestInstance
): EventHandler | null => {
const touchResponder = isTouchResponder(element)
@@ -84,7 +84,7 @@ const findEventHandler = (
return null;
}
- return findEventHandler(element.parent, eventName, callsite, touchResponder);
+ return findEventHandler(element.parent, eventName, touchResponder);
};
const getEventHandler = (
@@ -106,11 +106,9 @@ const getEventHandler = (
const invokeEvent = (
element: ReactTestInstance,
eventName: string,
- callsite?: any,
...data: Array
) => {
- const handler = findEventHandler(element, eventName, callsite);
-
+ const handler = findEventHandler(element, eventName);
if (!handler) {
return;
}
@@ -127,23 +125,61 @@ const invokeEvent = (
const toEventHandlerName = (eventName: string) =>
`on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
-const pressHandler = (element: ReactTestInstance, ...data: Array): void =>
- invokeEvent(element, 'press', pressHandler, ...data);
-const changeTextHandler = (
- element: ReactTestInstance,
- ...data: Array
-): void => invokeEvent(element, 'changeText', changeTextHandler, ...data);
-const scrollHandler = (element: ReactTestInstance, ...data: Array): void =>
- invokeEvent(element, 'scroll', scrollHandler, ...data);
+const getCoreEventName = (eventOrHandlerName: string) => {
+ if (
+ eventOrHandlerName.startsWith('on') &&
+ eventOrHandlerName[2] === eventOrHandlerName[2]?.toUpperCase()
+ ) {
+ const coreName = eventOrHandlerName.slice(2);
+ return coreName.charAt(0).toLowerCase() + coreName.slice(1);
+ }
+
+ return eventOrHandlerName;
+};
const fireEvent = (
element: ReactTestInstance,
eventName: string,
- ...data: Array
-): void => invokeEvent(element, eventName, fireEvent, ...data);
+ ...data: any[]
+): void => invokeEvent(element, eventName, ...data);
-fireEvent.press = pressHandler;
-fireEvent.changeText = changeTextHandler;
-fireEvent.scroll = scrollHandler;
+function getEventData(eventName: string, ...data: any[]) {
+ // Legacy mode where user passes 2+ args
+ if (data.length > 1) {
+ return data;
+ }
+
+ // Legacy mode where user passes full event object
+ if (data[0]?.nativeEvent != null) {
+ return [data[0]];
+ }
+
+ // Mode where user passes optional event init data.
+ const name = getCoreEventName(eventName);
+ return [createEvent(name, data[0])];
+}
+
+function invokeEventWithDefaultData(
+ element: ReactTestInstance,
+ eventName: string,
+ ...data: any[]
+) {
+ const eventData = getEventData(eventName, ...data);
+ return invokeEvent(element, eventName, ...eventData);
+}
+
+// Regular events:
+fireEvent.press = (element: ReactTestInstance, ...data: any[]) => {
+ return invokeEventWithDefaultData(element, 'press', ...data);
+};
+
+fireEvent.scroll = (element: ReactTestInstance, ...data: any[]) => {
+ return invokeEventWithDefaultData(element, 'scroll', ...data);
+};
+
+// changeText is not a regular event, as the callback args is just the changed not, and not an Event object
+fireEvent.changeText = (element: ReactTestInstance, text: string) => {
+ return invokeEvent(element, 'changeText', text);
+};
export default fireEvent;
diff --git a/src/helpers/create-event.ts b/src/helpers/create-event.ts
new file mode 100644
index 000000000..4fb8a0ef3
--- /dev/null
+++ b/src/helpers/create-event.ts
@@ -0,0 +1,35 @@
+// Based on: https://reactnative.dev/docs/pressevent#example
+export const defaultPressEvent = {
+ changedTouches: [],
+ identifier: 0,
+ locationX: 0,
+ locationY: 0,
+ pageX: 0,
+ pageY: 0,
+ targe: 0,
+ timestamp: 0,
+ touches: [],
+};
+
+// Based on: https://reactnative.dev/docs/scrollview#onscroll
+export const defaultScrollEvent = {
+ contentInset: { bottom: 0, left: 0, right: 0, top: 0 },
+ contentOffset: { x: 0, y: 0 },
+ contentSize: { height: 0, width: 0 },
+ layoutMeasurement: { height: 0, width: 0 },
+ zoomScale: 0,
+};
+
+const eventMap: Record = {
+ press: { ...defaultPressEvent },
+ scroll: { ...defaultScrollEvent },
+};
+
+export function createEvent(eventName: string, eventInit?: object) {
+ return {
+ nativeEvent: {
+ ...eventMap[eventName],
+ ...eventInit,
+ },
+ };
+}