@@ -16,7 +16,6 @@ import {
1616import { fireEvent , render , screen } from '..' ;
1717import { nativeState } from '../native-state' ;
1818
19- // Shared test data
2019const layoutEvent = { nativeEvent : { layout : { width : 100 , height : 100 } } } ;
2120const 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-
7447test ( '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
15165describe ( '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
236150describe ( '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+
336333describe ( '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
516513describe ( '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', () => {
638633describe ( '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