Skip to content

Commit 907f6b5

Browse files
committed
.
1 parent 2c07a47 commit 907f6b5

File tree

1 file changed

+98
-107
lines changed

1 file changed

+98
-107
lines changed

src/__tests__/fire-event.test.tsx

Lines changed: 98 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
import { fireEvent, render, screen } from '..';
1717
import { nativeState } from '../native-state';
1818

19-
// Shared test data
2019
const layoutEvent = { nativeEvent: { layout: { width: 100, height: 100 } } };
2120
const pressEventData = { nativeEvent: { pageX: 20, pageY: 30 } };
2221

@@ -45,107 +44,22 @@ test('fireEvent passes multiple parameters to handler', async () => {
4544
expect(handlePress).toHaveBeenCalledWith('param1', 'param2', 'param3');
4645
});
4746

48-
test('fireEvent bubbles event to parent handler', async () => {
49-
const onPress = jest.fn();
50-
await render(
51-
<TouchableOpacity onPress={onPress}>
52-
<Text>Press me</Text>
53-
</TouchableOpacity>,
54-
);
55-
await fireEvent.press(screen.getByText('Press me'));
56-
expect(onPress).toHaveBeenCalled();
57-
});
58-
59-
test('fireEvent calls handler on element when both element and parent have handlers', async () => {
60-
const childHandler = jest.fn();
61-
const parentHandler = jest.fn();
62-
await render(
63-
<TouchableOpacity onPress={parentHandler}>
64-
<Pressable testID="child" onPress={childHandler}>
65-
<Text>Press me</Text>
66-
</Pressable>
67-
</TouchableOpacity>,
68-
);
69-
await fireEvent.press(screen.getByTestId('child'));
70-
expect(childHandler).toHaveBeenCalledTimes(1);
71-
expect(parentHandler).not.toHaveBeenCalled();
72-
});
73-
7447
test('fireEvent returns handler return value', async () => {
7548
const handler = jest.fn().mockReturnValue('result');
7649
await render(<Pressable testID="btn" onPress={handler} />);
7750
const result = await fireEvent.press(screen.getByTestId('btn'));
7851
expect(result).toBe('result');
7952
});
8053

81-
test('fireEvent returns undefined when handler does not return a value', async () => {
82-
const handler = jest.fn();
83-
await render(<Pressable testID="btn" onPress={handler} />);
84-
const result = await fireEvent.press(screen.getByTestId('btn'));
85-
expect(result).toBeUndefined();
86-
});
87-
88-
test('fireEvent does nothing when element is unmounted', async () => {
54+
test('fireEvent bubbles event to parent handler', async () => {
8955
const onPress = jest.fn();
90-
const { unmount } = await render(<Pressable testID="btn" onPress={onPress} />);
91-
const element = screen.getByTestId('btn');
92-
93-
await unmount();
94-
95-
await fireEvent.press(element);
96-
expect(onPress).not.toHaveBeenCalled();
97-
});
98-
99-
test('fireEvent does not update native state when element is unmounted', async () => {
100-
const { unmount } = await render(<TextInput testID="input" />);
101-
const input = screen.getByTestId('input');
102-
103-
await unmount();
104-
105-
await fireEvent.changeText(input, 'should not update');
106-
expect(nativeState.valueForElement.get(input)).toBeUndefined();
107-
});
108-
109-
test('fireEvent does not throw when called with non-existent event name', async () => {
110-
await render(<Pressable testID="btn" />);
111-
const element = screen.getByTestId('btn');
112-
// Should not throw, just do nothing
113-
await expect(fireEvent(element, 'nonExistentEvent' as any)).resolves.toBeUndefined();
114-
});
115-
116-
test('fireEvent handles handler that throws gracefully', async () => {
117-
const error = new Error('Handler error');
118-
const onPress = jest.fn(() => {
119-
throw error;
120-
});
121-
await render(<Pressable testID="btn" onPress={onPress} />);
122-
await expect(fireEvent.press(screen.getByTestId('btn'))).rejects.toThrow('Handler error');
123-
expect(onPress).toHaveBeenCalledTimes(1);
124-
});
125-
126-
test('fireEvent fires custom event (onCustomEvent) on composite component', async () => {
127-
const CustomComponent = ({ onCustomEvent }: { onCustomEvent: (data: string) => void }) => (
128-
<TouchableOpacity onPress={() => onCustomEvent('event data')}>
129-
<Text>Custom</Text>
130-
</TouchableOpacity>
131-
);
132-
const handler = jest.fn();
133-
await render(<CustomComponent onCustomEvent={handler} />);
134-
// fireEvent accepts both 'customEvent' and 'onCustomEvent' event names
135-
await fireEvent(screen.getByText('Custom'), 'customEvent', 'event data');
136-
expect(handler).toHaveBeenCalledWith('event data');
137-
});
138-
139-
test('fireEvent fires event with custom prop name (handlePress) on composite component', async () => {
140-
const MyButton = ({ handlePress }: { handlePress: () => void }) => (
141-
<TouchableOpacity onPress={handlePress}>
142-
<Text>Button</Text>
143-
</TouchableOpacity>
56+
await render(
57+
<TouchableOpacity onPress={onPress}>
58+
<Text>Press me</Text>
59+
</TouchableOpacity>,
14460
);
145-
const handler = jest.fn();
146-
await render(<MyButton handlePress={handler} />);
147-
await fireEvent(screen.getByText('Button'), 'handlePress');
148-
expect(handler).toHaveBeenCalled();
61+
await fireEvent.press(screen.getByText('Press me'));
62+
expect(onPress).toHaveBeenCalled();
14963
});
15064

15165
describe('fireEvent.press', () => {
@@ -215,6 +129,14 @@ describe('fireEvent.changeText', () => {
215129
expect(nativeState.valueForElement.get(input)).toBe('new text');
216130
});
217131

132+
test('updates native state for uncontrolled TextInput', async () => {
133+
await render(<TextInput testID="input" />);
134+
const input = screen.getByTestId('input');
135+
await fireEvent.changeText(input, 'hello');
136+
expect(input).toHaveDisplayValue('hello');
137+
expect(nativeState.valueForElement.get(input)).toBe('hello');
138+
});
139+
218140
test('does not fire on non-editable TextInput', async () => {
219141
const onChangeText = jest.fn();
220142
await render(<TextInput testID="input" editable={false} onChangeText={onChangeText} />);
@@ -223,14 +145,6 @@ describe('fireEvent.changeText', () => {
223145
expect(onChangeText).not.toHaveBeenCalled();
224146
expect(nativeState.valueForElement.get(input)).toBeUndefined();
225147
});
226-
227-
test('updates native state for uncontrolled TextInput', async () => {
228-
await render(<TextInput testID="input" />);
229-
const input = screen.getByTestId('input');
230-
await fireEvent.changeText(input, 'hello');
231-
expect(input).toHaveDisplayValue('hello');
232-
expect(nativeState.valueForElement.get(input)).toBe('hello');
233-
});
234148
});
235149

236150
describe('fireEvent.scroll', () => {
@@ -333,6 +247,89 @@ describe('fireEvent.scroll', () => {
333247
});
334248
});
335249

250+
test('fireEvent fires custom event (onCustomEvent) on composite component', async () => {
251+
const CustomComponent = ({ onCustomEvent }: { onCustomEvent: (data: string) => void }) => (
252+
<TouchableOpacity onPress={() => onCustomEvent('event data')}>
253+
<Text>Custom</Text>
254+
</TouchableOpacity>
255+
);
256+
const handler = jest.fn();
257+
await render(<CustomComponent onCustomEvent={handler} />);
258+
await fireEvent(screen.getByText('Custom'), 'customEvent', 'event data');
259+
expect(handler).toHaveBeenCalledWith('event data');
260+
});
261+
262+
test('fireEvent fires event with custom prop name (handlePress) on composite component', async () => {
263+
const MyButton = ({ handlePress }: { handlePress: () => void }) => (
264+
<TouchableOpacity onPress={handlePress}>
265+
<Text>Button</Text>
266+
</TouchableOpacity>
267+
);
268+
const handler = jest.fn();
269+
await render(<MyButton handlePress={handler} />);
270+
await fireEvent(screen.getByText('Button'), 'handlePress');
271+
expect(handler).toHaveBeenCalled();
272+
});
273+
274+
test('fireEvent returns undefined when handler does not return a value', async () => {
275+
const handler = jest.fn();
276+
await render(<Pressable testID="btn" onPress={handler} />);
277+
const result = await fireEvent.press(screen.getByTestId('btn'));
278+
expect(result).toBeUndefined();
279+
});
280+
281+
test('fireEvent calls handler on element when both element and parent have handlers', async () => {
282+
const childHandler = jest.fn();
283+
const parentHandler = jest.fn();
284+
await render(
285+
<TouchableOpacity onPress={parentHandler}>
286+
<Pressable testID="child" onPress={childHandler}>
287+
<Text>Press me</Text>
288+
</Pressable>
289+
</TouchableOpacity>,
290+
);
291+
await fireEvent.press(screen.getByTestId('child'));
292+
expect(childHandler).toHaveBeenCalledTimes(1);
293+
expect(parentHandler).not.toHaveBeenCalled();
294+
});
295+
296+
test('fireEvent does nothing when element is unmounted', async () => {
297+
const onPress = jest.fn();
298+
const { unmount } = await render(<Pressable testID="btn" onPress={onPress} />);
299+
const element = screen.getByTestId('btn');
300+
301+
await unmount();
302+
303+
await fireEvent.press(element);
304+
expect(onPress).not.toHaveBeenCalled();
305+
});
306+
307+
test('fireEvent does not update native state when element is unmounted', async () => {
308+
const { unmount } = await render(<TextInput testID="input" />);
309+
const input = screen.getByTestId('input');
310+
311+
await unmount();
312+
313+
await fireEvent.changeText(input, 'should not update');
314+
expect(nativeState.valueForElement.get(input)).toBeUndefined();
315+
});
316+
317+
test('fireEvent does not throw when called with non-existent event name', async () => {
318+
await render(<Pressable testID="btn" />);
319+
const element = screen.getByTestId('btn');
320+
await expect(fireEvent(element, 'nonExistentEvent' as any)).resolves.toBeUndefined();
321+
});
322+
323+
test('fireEvent handles handler that throws gracefully', async () => {
324+
const error = new Error('Handler error');
325+
const onPress = jest.fn(() => {
326+
throw error;
327+
});
328+
await render(<Pressable testID="btn" onPress={onPress} />);
329+
await expect(fireEvent.press(screen.getByTestId('btn'))).rejects.toThrow('Handler error');
330+
expect(onPress).toHaveBeenCalledTimes(1);
331+
});
332+
336333
describe('disabled elements', () => {
337334
test('does not fire on disabled TouchableOpacity', async () => {
338335
const onPress = jest.fn();
@@ -514,8 +511,6 @@ describe('pointerEvents prop', () => {
514511
});
515512

516513
describe('non-editable TextInput', () => {
517-
// Helper components used to test that fireEvent correctly traverses
518-
// composite component wrappers to find the underlying TextInput
519514
function WrappedTextInput(props: TextInputProps) {
520515
return <TextInput {...props} />;
521516
}
@@ -638,9 +633,6 @@ describe('non-editable TextInput', () => {
638633
describe('responder system', () => {
639634
test('responder handlers are checked during event handling', async () => {
640635
const onPress = jest.fn();
641-
// Tests that responder handlers (onStartShouldSetResponder) are evaluated
642-
// during event handling. The responder system affects event propagation,
643-
// but handlers directly on the element will still fire.
644636
await render(
645637
<View onStartShouldSetResponder={() => false}>
646638
<Pressable onPress={onPress}>
@@ -649,7 +641,6 @@ describe('responder system', () => {
649641
</View>,
650642
);
651643
await fireEvent.press(screen.getByTestId('text'));
652-
// Handler on Pressable fires because it's directly on the element
653644
expect(onPress).toHaveBeenCalled();
654645
});
655646

0 commit comments

Comments
 (0)