0
# User Interactions
1
2
Realistic user interaction simulation supporting press events, text input, scrolling, and other React Native-specific gestures. Provides both synchronous fireEvent API and more realistic asynchronous userEvent API.
3
4
## Capabilities
5
6
### FireEvent API
7
8
Synchronous event firing utility for immediate event simulation - faster but less realistic than userEvent.
9
10
```typescript { .api }
11
/**
12
* Synchronous event firing utility
13
* Fires events immediately without realistic timing or validation
14
*/
15
declare const fireEvent: {
16
/** Fire press event on pressable elements */
17
press(element: ReactTestInstance): void;
18
19
/** Fire long press event */
20
longPress(element: ReactTestInstance): void;
21
22
/** Fire text change event on TextInput elements */
23
changeText(element: ReactTestInstance, text: string): void;
24
25
/** Fire scroll event on scrollable elements */
26
scroll(element: ReactTestInstance, eventData?: ScrollEventData): void;
27
28
/** Fire focus event on focusable elements */
29
focus(element: ReactTestInstance): void;
30
31
/** Fire blur event on focusable elements */
32
blur(element: ReactTestInstance): void;
33
34
/** Fire layout event */
35
layout(element: ReactTestInstance, layoutData: LayoutEventData): void;
36
37
/** Fire content size change event */
38
contentSizeChange(element: ReactTestInstance, contentSize: ContentSizeData): void;
39
40
/** Fire end editing event on TextInput */
41
endEditing(element: ReactTestInstance, text?: string): void;
42
43
/** Fire selection change event on TextInput */
44
selectionChange(element: ReactTestInstance, selection: SelectionData): void;
45
46
/** Fire refresh event on RefreshControl */
47
refresh(element: ReactTestInstance): void;
48
49
/** Fire momentum scroll begin event */
50
momentumScrollBegin(element: ReactTestInstance): void;
51
52
/** Fire momentum scroll end event */
53
momentumScrollEnd(element: ReactTestInstance): void;
54
55
/** Fire scroll begin drag event */
56
scrollBeginDrag(element: ReactTestInstance): void;
57
58
/** Fire scroll end drag event */
59
scrollEndDrag(element: ReactTestInstance): void;
60
};
61
62
/**
63
* Async version of fireEvent for more realistic timing
64
*/
65
declare const fireEventAsync: typeof fireEvent;
66
67
interface ScrollEventData {
68
nativeEvent: {
69
contentOffset: { x: number; y: number };
70
contentSize: { width: number; height: number };
71
layoutMeasurement: { width: number; height: number };
72
};
73
}
74
75
interface LayoutEventData {
76
nativeEvent: {
77
layout: { x: number; y: number; width: number; height: number };
78
};
79
}
80
81
interface ContentSizeData {
82
nativeEvent: {
83
contentSize: { width: number; height: number };
84
};
85
}
86
87
interface SelectionData {
88
nativeEvent: {
89
selection: { start: number; end: number };
90
};
91
}
92
```
93
94
**Usage Examples:**
95
96
```typescript
97
import { render, screen, fireEvent } from "@testing-library/react-native";
98
99
test("fireEvent interactions", () => {
100
const handlePress = jest.fn();
101
const handleTextChange = jest.fn();
102
const handleScroll = jest.fn();
103
104
render(
105
<View>
106
<Pressable onPress={handlePress} testID="button">
107
<Text>Press Me</Text>
108
</Pressable>
109
<TextInput
110
onChangeText={handleTextChange}
111
testID="input"
112
placeholder="Type here"
113
/>
114
<ScrollView onScroll={handleScroll} testID="scroll">
115
<Text>Scrollable content</Text>
116
</ScrollView>
117
</View>
118
);
119
120
// Press button
121
const button = screen.getByTestId("button");
122
fireEvent.press(button);
123
expect(handlePress).toHaveBeenCalledTimes(1);
124
125
// Change text
126
const input = screen.getByTestId("input");
127
fireEvent.changeText(input, "Hello World");
128
expect(handleTextChange).toHaveBeenCalledWith("Hello World");
129
130
// Scroll
131
const scrollView = screen.getByTestId("scroll");
132
fireEvent.scroll(scrollView, {
133
nativeEvent: {
134
contentOffset: { x: 0, y: 100 },
135
contentSize: { width: 300, height: 1000 },
136
layoutMeasurement: { width: 300, height: 400 }
137
}
138
});
139
expect(handleScroll).toHaveBeenCalled();
140
141
// Long press
142
fireEvent.longPress(button);
143
144
// Focus and blur
145
fireEvent.focus(input);
146
fireEvent.blur(input);
147
148
// End editing
149
fireEvent.endEditing(input, "Final text");
150
});
151
```
152
153
### UserEvent API
154
155
More realistic user interaction simulation with proper timing, validation, and event sequences.
156
157
```typescript { .api }
158
/**
159
* Realistic user event simulation
160
* Provides more authentic user interactions with proper timing and validation
161
*/
162
declare const userEvent: {
163
/** Create configured user event instance */
164
setup(config?: UserEventConfig): UserEventInstance;
165
166
// Direct access methods for v13 compatibility
167
/** Press an element */
168
press(element: ReactTestInstance): Promise<void>;
169
170
/** Long press an element with optional configuration */
171
longPress(element: ReactTestInstance, options?: PressOptions): Promise<void>;
172
173
/** Type text into an input element */
174
type(element: ReactTestInstance, text: string, options?: TypeOptions): Promise<void>;
175
176
/** Clear text from an input element */
177
clear(element: ReactTestInstance): Promise<void>;
178
179
/** Paste text into an input element */
180
paste(element: ReactTestInstance, text: string): Promise<void>;
181
182
/** Scroll an element to specific position */
183
scrollTo(element: ReactTestInstance, options: ScrollToOptions): Promise<void>;
184
};
185
186
interface UserEventConfig {
187
/** Delay between keystrokes when typing (ms) */
188
delay?: number;
189
190
/** Whether to skip validation of element state */
191
skipValidation?: boolean;
192
193
/** Custom press duration for long press (ms) */
194
longPressDelay?: number;
195
}
196
197
interface UserEventInstance {
198
/** Press an element */
199
press(element: ReactTestInstance): Promise<void>;
200
201
/** Long press with options */
202
longPress(element: ReactTestInstance, options?: PressOptions): Promise<void>;
203
204
/** Type text with realistic timing */
205
type(element: ReactTestInstance, text: string, options?: TypeOptions): Promise<void>;
206
207
/** Clear text input */
208
clear(element: ReactTestInstance): Promise<void>;
209
210
/** Paste text */
211
paste(element: ReactTestInstance, text: string): Promise<void>;
212
213
/** Scroll to position */
214
scrollTo(element: ReactTestInstance, options: ScrollToOptions): Promise<void>;
215
}
216
```
217
218
**Usage Examples:**
219
220
```typescript
221
import { render, screen, userEvent } from "@testing-library/react-native";
222
223
test("userEvent interactions", async () => {
224
const user = userEvent.setup({ delay: 10 });
225
226
const handlePress = jest.fn();
227
const handleTextChange = jest.fn();
228
229
render(
230
<View>
231
<Pressable onPress={handlePress} testID="button">
232
<Text>Press Me</Text>
233
</Pressable>
234
<TextInput
235
onChangeText={handleTextChange}
236
testID="input"
237
placeholder="Type here"
238
/>
239
</View>
240
);
241
242
// Realistic button press
243
const button = screen.getByTestId("button");
244
await user.press(button);
245
expect(handlePress).toHaveBeenCalledTimes(1);
246
247
// Realistic text typing with delays
248
const input = screen.getByTestId("input");
249
await user.type(input, "Hello World");
250
expect(input.props.value).toBe("Hello World");
251
252
// Clear input
253
await user.clear(input);
254
expect(input.props.value).toBe("");
255
256
// Paste text
257
await user.paste(input, "Pasted content");
258
expect(input.props.value).toBe("Pasted content");
259
260
// Long press with custom duration
261
await user.longPress(button, { duration: 1000 });
262
});
263
264
test("direct userEvent methods", async () => {
265
render(<Pressable testID="button"><Text>Press</Text></Pressable>);
266
267
// Direct method usage (v13 compatibility)
268
const button = screen.getByTestId("button");
269
await userEvent.press(button);
270
await userEvent.longPress(button);
271
});
272
```
273
274
### Press Interactions
275
276
Detailed press interaction options and configurations.
277
278
```typescript { .api }
279
/**
280
* Press an element with realistic touch behavior
281
* @param element - Element to press
282
* @returns Promise that resolves when press is complete
283
*/
284
function press(element: ReactTestInstance): Promise<void>;
285
286
/**
287
* Long press an element with configurable duration
288
* @param element - Element to long press
289
* @param options - Long press configuration options
290
* @returns Promise that resolves when long press is complete
291
*/
292
function longPress(element: ReactTestInstance, options?: PressOptions): Promise<void>;
293
294
interface PressOptions {
295
/** Duration of long press in milliseconds (default: 500) */
296
duration?: number;
297
}
298
```
299
300
**Usage Examples:**
301
302
```typescript
303
test("press interactions", async () => {
304
const user = userEvent.setup();
305
const handlePress = jest.fn();
306
const handleLongPress = jest.fn();
307
308
render(
309
<Pressable
310
onPress={handlePress}
311
onLongPress={handleLongPress}
312
testID="interactive-button"
313
>
314
<Text>Interactive Button</Text>
315
</Pressable>
316
);
317
318
const button = screen.getByTestId("interactive-button");
319
320
// Standard press
321
await user.press(button);
322
expect(handlePress).toHaveBeenCalledTimes(1);
323
324
// Long press with default duration (500ms)
325
await user.longPress(button);
326
expect(handleLongPress).toHaveBeenCalledTimes(1);
327
328
// Long press with custom duration
329
await user.longPress(button, { duration: 1000 });
330
expect(handleLongPress).toHaveBeenCalledTimes(2);
331
});
332
```
333
334
### Text Input Interactions
335
336
Comprehensive text input simulation with realistic typing, clearing, and pasting.
337
338
```typescript { .api }
339
/**
340
* Type text into an input element with realistic timing
341
* @param element - TextInput element to type into
342
* @param text - Text to type
343
* @param options - Typing configuration options
344
* @returns Promise that resolves when typing is complete
345
*/
346
function type(element: ReactTestInstance, text: string, options?: TypeOptions): Promise<void>;
347
348
/**
349
* Clear all text from an input element
350
* @param element - TextInput element to clear
351
* @returns Promise that resolves when clearing is complete
352
*/
353
function clear(element: ReactTestInstance): Promise<void>;
354
355
/**
356
* Paste text into an input element
357
* @param element - TextInput element to paste into
358
* @param text - Text to paste
359
* @returns Promise that resolves when pasting is complete
360
*/
361
function paste(element: ReactTestInstance, text: string): Promise<void>;
362
363
interface TypeOptions {
364
/** Delay between keystrokes in milliseconds */
365
delay?: number;
366
367
/** Whether to skip element validation */
368
skipValidation?: boolean;
369
370
/** Whether to clear existing text before typing */
371
clearFirst?: boolean;
372
}
373
```
374
375
**Usage Examples:**
376
377
```typescript
378
test("text input interactions", async () => {
379
const user = userEvent.setup();
380
const handleTextChange = jest.fn();
381
const handleSelectionChange = jest.fn();
382
383
render(
384
<TextInput
385
testID="text-input"
386
placeholder="Enter text"
387
onChangeText={handleTextChange}
388
onSelectionChange={handleSelectionChange}
389
multiline
390
/>
391
);
392
393
const input = screen.getByTestId("text-input");
394
395
// Type with default timing
396
await user.type(input, "Hello");
397
expect(handleTextChange).toHaveBeenLastCalledWith("Hello");
398
399
// Type with custom delay
400
await user.type(input, " World", { delay: 50 });
401
expect(handleTextChange).toHaveBeenLastCalledWith("Hello World");
402
403
// Clear input
404
await user.clear(input);
405
expect(handleTextChange).toHaveBeenLastCalledWith("");
406
407
// Type after clearing
408
await user.type(input, "New text", { clearFirst: true });
409
expect(handleTextChange).toHaveBeenLastCalledWith("New text");
410
411
// Paste text
412
await user.paste(input, "\nPasted line");
413
expect(handleTextChange).toHaveBeenLastCalledWith("New text\nPasted line");
414
});
415
416
test("text input with validation", async () => {
417
const user = userEvent.setup();
418
419
render(
420
<TextInput
421
testID="disabled-input"
422
editable={false}
423
placeholder="Disabled input"
424
/>
425
);
426
427
const disabledInput = screen.getByTestId("disabled-input");
428
429
// This will throw an error because input is not editable
430
await expect(user.type(disabledInput, "text")).rejects.toThrow();
431
432
// Skip validation to force typing
433
await user.type(disabledInput, "forced text", { skipValidation: true });
434
});
435
```
436
437
### Scroll Interactions
438
439
Realistic scrolling simulation for ScrollView and other scrollable components.
440
441
```typescript { .api }
442
/**
443
* Scroll an element to a specific position
444
* @param element - ScrollView or scrollable element
445
* @param options - Scroll target options
446
* @returns Promise that resolves when scrolling is complete
447
*/
448
function scrollTo(element: ReactTestInstance, options: ScrollToOptions): Promise<void>;
449
450
interface ScrollToOptions {
451
/** Horizontal scroll position */
452
x?: number;
453
454
/** Vertical scroll position */
455
y?: number;
456
457
/** Whether to animate the scroll */
458
animated?: boolean;
459
}
460
```
461
462
**Usage Examples:**
463
464
```typescript
465
test("scroll interactions", async () => {
466
const user = userEvent.setup();
467
const handleScroll = jest.fn();
468
const handleMomentumScrollEnd = jest.fn();
469
470
render(
471
<ScrollView
472
testID="scroll-view"
473
onScroll={handleScroll}
474
onMomentumScrollEnd={handleMomentumScrollEnd}
475
scrollEventThrottle={16}
476
>
477
<View style={{ height: 2000 }}>
478
<Text>Long scrollable content</Text>
479
</View>
480
</ScrollView>
481
);
482
483
const scrollView = screen.getByTestId("scroll-view");
484
485
// Scroll vertically
486
await user.scrollTo(scrollView, { y: 500 });
487
expect(handleScroll).toHaveBeenCalled();
488
489
// Scroll horizontally
490
await user.scrollTo(scrollView, { x: 200 });
491
492
// Scroll to specific position with animation
493
await user.scrollTo(scrollView, {
494
x: 100,
495
y: 300,
496
animated: true
497
});
498
499
// Scroll back to top
500
await user.scrollTo(scrollView, { x: 0, y: 0 });
501
});
502
```
503
504
### Event Validation and Utilities
505
506
Utilities for validating element states and event capabilities.
507
508
```typescript { .api }
509
/**
510
* Check if element is a touch responder
511
* @param element - Element to check
512
* @returns True if element can respond to touch events
513
*/
514
function isTouchResponder(element: ReactTestInstance): boolean;
515
516
/**
517
* Check if event is enabled for element
518
* @param element - Element to check
519
* @param eventName - Event name to validate
520
* @returns True if event can be fired on element
521
*/
522
function isEventEnabled(
523
element: ReactTestInstance,
524
eventName: string
525
): boolean;
526
```
527
528
**Usage Examples:**
529
530
```typescript
531
import { render, screen, isTouchResponder, isEventEnabled } from "@testing-library/react-native";
532
533
test("event validation utilities", () => {
534
render(
535
<View>
536
<Pressable testID="pressable">
537
<Text>Pressable</Text>
538
</Pressable>
539
<View testID="plain-view">
540
<Text>Plain View</Text>
541
</View>
542
<TextInput testID="input" editable={false} />
543
<View pointerEvents="none" testID="no-pointer-events">
544
<Text>No Pointer Events</Text>
545
</View>
546
</View>
547
);
548
549
const pressable = screen.getByTestId("pressable");
550
const plainView = screen.getByTestId("plain-view");
551
const input = screen.getByTestId("input");
552
const noPointerView = screen.getByTestId("no-pointer-events");
553
554
// Check touch responder capability
555
expect(isTouchResponder(pressable)).toBe(true);
556
expect(isTouchResponder(plainView)).toBe(false);
557
expect(isTouchResponder(input)).toBe(true); // TextInput is always touch responder
558
559
// Check specific event capabilities
560
expect(isEventEnabled(pressable, "press")).toBe(true);
561
expect(isEventEnabled(noPointerView, "press")).toBe(false);
562
expect(isEventEnabled(input, "changeText")).toBe(false); // Not editable
563
});
564
```
565
566
## Configuration and Setup
567
568
Global configuration for user event behavior and timing.
569
570
```typescript { .api }
571
/**
572
* Create configured user event instance
573
* @param config - User event configuration options
574
* @returns Configured user event instance
575
*/
576
function setup(config?: UserEventConfig): UserEventInstance;
577
578
interface UserEventConfig {
579
/** Default delay between keystrokes when typing (ms) */
580
delay?: number;
581
582
/** Whether to skip element state validation by default */
583
skipValidation?: boolean;
584
585
/** Default duration for long press interactions (ms) */
586
longPressDelay?: number;
587
588
/** Whether to advance timers automatically in fake timer environments */
589
advanceTimers?: boolean;
590
}
591
```
592
593
**Usage Examples:**
594
595
```typescript
596
test("user event configuration", async () => {
597
// Create instance with custom configuration
598
const fastUser = userEvent.setup({
599
delay: 5, // Fast typing
600
longPressDelay: 200 // Short long press
601
});
602
603
const slowUser = userEvent.setup({
604
delay: 100, // Slow typing
605
longPressDelay: 1000 // Long press
606
});
607
608
const permissiveUser = userEvent.setup({
609
skipValidation: true // Skip all validation
610
});
611
612
render(<TextInput testID="input" placeholder="Type here" />);
613
const input = screen.getByTestId("input");
614
615
// Fast typing
616
await fastUser.type(input, "Fast text");
617
618
// Slow typing
619
await slowUser.type(input, "Slow text", { clearFirst: true });
620
621
// Type in disabled input (normally would throw)
622
render(<TextInput testID="disabled" editable={false} />);
623
const disabled = screen.getByTestId("disabled");
624
await permissiveUser.type(disabled, "Force type");
625
});
626
```