0
# Firing Events
1
2
Simulate user interactions with automatic act() wrapping for React state updates.
3
4
## API
5
6
Main utility for firing DOM events. Automatically wrapped in `act()` for proper React state updates.
7
8
```typescript { .api }
9
/**
10
* Fire a DOM event on an element
11
* @param element - Target element
12
* @param event - Event object to fire
13
* @returns true if event was not cancelled
14
*/
15
const fireEvent: {
16
(element: HTMLElement, event: Event): boolean;
17
18
// Mouse Events
19
click(element: HTMLElement, options?: MouseEventInit): void;
20
dblClick(element: HTMLElement, options?: MouseEventInit): void;
21
mouseDown(element: HTMLElement, options?: MouseEventInit): void;
22
mouseUp(element: HTMLElement, options?: MouseEventInit): void;
23
mouseMove(element: HTMLElement, options?: MouseEventInit): void;
24
mouseOver(element: HTMLElement, options?: MouseEventInit): void;
25
mouseOut(element: HTMLElement, options?: MouseEventInit): void;
26
mouseEnter(element: HTMLElement, options?: MouseEventInit): void;
27
mouseLeave(element: HTMLElement, options?: MouseEventInit): void;
28
contextMenu(element: HTMLElement, options?: MouseEventInit): void;
29
wheel(element: HTMLElement, options?: WheelEventInit): void;
30
31
// Pointer Events
32
pointerDown(element: HTMLElement, options?: PointerEventInit): void;
33
pointerUp(element: HTMLElement, options?: PointerEventInit): void;
34
pointerMove(element: HTMLElement, options?: PointerEventInit): void;
35
pointerOver(element: HTMLElement, options?: PointerEventInit): void;
36
pointerOut(element: HTMLElement, options?: PointerEventInit): void;
37
pointerEnter(element: HTMLElement, options?: PointerEventInit): void;
38
pointerLeave(element: HTMLElement, options?: PointerEventInit): void;
39
pointerCancel(element: HTMLElement, options?: PointerEventInit): void;
40
gotPointerCapture(element: HTMLElement, options?: PointerEventInit): void;
41
lostPointerCapture(element: HTMLElement, options?: PointerEventInit): void;
42
43
// Keyboard Events
44
keyDown(element: HTMLElement, options?: KeyboardEventInit): void;
45
keyUp(element: HTMLElement, options?: KeyboardEventInit): void;
46
keyPress(element: HTMLElement, options?: KeyboardEventInit): void;
47
48
// Focus Events
49
focus(element: HTMLElement, options?: FocusEventInit): void;
50
blur(element: HTMLElement, options?: FocusEventInit): void;
51
focusIn(element: HTMLElement, options?: FocusEventInit): void;
52
focusOut(element: HTMLElement, options?: FocusEventInit): void;
53
54
// Form Events
55
change(element: HTMLElement, options?: EventInit): void;
56
input(element: HTMLElement, options?: InputEventInit): void;
57
invalid(element: HTMLElement, options?: EventInit): void;
58
submit(element: HTMLElement, options?: EventInit): void;
59
reset(element: HTMLElement, options?: EventInit): void;
60
select(element: HTMLElement, options?: EventInit): void;
61
62
// Clipboard Events
63
copy(element: HTMLElement, options?: ClipboardEventInit): void;
64
cut(element: HTMLElement, options?: ClipboardEventInit): void;
65
paste(element: HTMLElement, options?: ClipboardEventInit): void;
66
67
// Composition Events
68
compositionStart(element: HTMLElement, options?: CompositionEventInit): void;
69
compositionUpdate(element: HTMLElement, options?: CompositionEventInit): void;
70
compositionEnd(element: HTMLElement, options?: CompositionEventInit): void;
71
72
// Drag Events
73
drag(element: HTMLElement, options?: DragEventInit): void;
74
dragEnd(element: HTMLElement, options?: DragEventInit): void;
75
dragEnter(element: HTMLElement, options?: DragEventInit): void;
76
dragExit(element: HTMLElement, options?: DragEventInit): void;
77
dragLeave(element: HTMLElement, options?: DragEventInit): void;
78
dragOver(element: HTMLElement, options?: DragEventInit): void;
79
dragStart(element: HTMLElement, options?: DragEventInit): void;
80
drop(element: HTMLElement, options?: DragEventInit): void;
81
82
// Touch Events
83
touchStart(element: HTMLElement, options?: TouchEventInit): void;
84
touchMove(element: HTMLElement, options?: TouchEventInit): void;
85
touchEnd(element: HTMLElement, options?: TouchEventInit): void;
86
touchCancel(element: HTMLElement, options?: TouchEventInit): void;
87
88
// Animation Events
89
animationStart(element: HTMLElement, options?: AnimationEventInit): void;
90
animationEnd(element: HTMLElement, options?: AnimationEventInit): void;
91
animationIteration(element: HTMLElement, options?: AnimationEventInit): void;
92
93
// Transition Events
94
transitionEnd(element: HTMLElement, options?: TransitionEventInit): void;
95
96
// Media Events
97
abort(element: HTMLElement, options?: EventInit): void;
98
canPlay(element: HTMLElement, options?: EventInit): void;
99
canPlayThrough(element: HTMLElement, options?: EventInit): void;
100
durationChange(element: HTMLElement, options?: EventInit): void;
101
emptied(element: HTMLElement, options?: EventInit): void;
102
encrypted(element: HTMLElement, options?: EventInit): void;
103
ended(element: HTMLElement, options?: EventInit): void;
104
error(element: HTMLElement, options?: EventInit): void;
105
load(element: HTMLElement, options?: EventInit): void;
106
loadedData(element: HTMLElement, options?: EventInit): void;
107
loadedMetadata(element: HTMLElement, options?: EventInit): void;
108
loadStart(element: HTMLElement, options?: EventInit): void;
109
pause(element: HTMLElement, options?: EventInit): void;
110
play(element: HTMLElement, options?: EventInit): void;
111
playing(element: HTMLElement, options?: EventInit): void;
112
progress(element: HTMLElement, options?: EventInit): void;
113
rateChange(element: HTMLElement, options?: EventInit): void;
114
seeked(element: HTMLElement, options?: EventInit): void;
115
seeking(element: HTMLElement, options?: EventInit): void;
116
stalled(element: HTMLElement, options?: EventInit): void;
117
suspend(element: HTMLElement, options?: EventInit): void;
118
timeUpdate(element: HTMLElement, options?: EventInit): void;
119
volumeChange(element: HTMLElement, options?: EventInit): void;
120
waiting(element: HTMLElement, options?: EventInit): void;
121
122
// Other Events
123
scroll(element: HTMLElement, options?: EventInit): void;
124
};
125
```
126
127
## Common Patterns
128
129
### Click Events
130
```typescript
131
const button = screen.getByRole('button', { name: /submit/i });
132
fireEvent.click(button);
133
134
// With modifier keys
135
fireEvent.click(button, { ctrlKey: true, shiftKey: true });
136
```
137
138
### Form Input
139
```typescript
140
const input = screen.getByLabelText(/email/i);
141
142
// Text input
143
fireEvent.change(input, { target: { value: 'user@example.com' } });
144
145
// Checkbox
146
const checkbox = screen.getByRole('checkbox');
147
fireEvent.click(checkbox);
148
149
// Select dropdown
150
const select = screen.getByLabelText(/country/i);
151
fireEvent.change(select, { target: { value: 'USA' } });
152
```
153
154
### Keyboard Events
155
```typescript
156
const input = screen.getByRole('textbox');
157
158
// Single key
159
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
160
fireEvent.keyDown(input, { key: 'Escape', code: 'Escape' });
161
162
// With modifiers
163
fireEvent.keyDown(input, {
164
key: 's',
165
code: 'KeyS',
166
ctrlKey: true,
167
});
168
```
169
170
### Focus/Blur
171
```typescript
172
const input = screen.getByRole('textbox');
173
174
fireEvent.focus(input);
175
expect(document.activeElement).toBe(input);
176
177
fireEvent.blur(input);
178
```
179
180
### Mouse Hover
181
```typescript
182
const button = screen.getByRole('button');
183
184
fireEvent.mouseEnter(button); // Shows hover state
185
fireEvent.mouseLeave(button); // Hides hover state
186
```
187
188
## Testing Patterns
189
190
### Button Click
191
```typescript
192
test('increments counter', () => {
193
render(<Counter />);
194
195
const button = screen.getByRole('button', { name: /increment/i });
196
fireEvent.click(button);
197
198
expect(screen.getByText('Count: 1')).toBeInTheDocument();
199
});
200
```
201
202
### Form Submission
203
```typescript
204
test('submits form', () => {
205
const handleSubmit = jest.fn();
206
render(<Form onSubmit={handleSubmit} />);
207
208
fireEvent.change(screen.getByLabelText(/email/i), {
209
target: { value: 'user@example.com' }
210
});
211
212
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
213
214
expect(handleSubmit).toHaveBeenCalledWith({
215
email: 'user@example.com'
216
});
217
});
218
```
219
220
### Keyboard Navigation
221
```typescript
222
test('navigates with keyboard', () => {
223
render(<Menu />);
224
225
const menu = screen.getByRole('menu');
226
227
fireEvent.keyDown(menu, { key: 'ArrowDown', code: 'ArrowDown' });
228
expect(screen.getByRole('menuitem', { name: 'Item 1' })).toHaveFocus();
229
230
fireEvent.keyDown(menu, { key: 'Enter', code: 'Enter' });
231
// Menu item activated
232
});
233
```
234
235
### Input Validation
236
```typescript
237
test('validates email on blur', () => {
238
render(<EmailInput />);
239
240
const input = screen.getByLabelText(/email/i);
241
242
fireEvent.change(input, { target: { value: 'invalid' } });
243
fireEvent.blur(input);
244
245
expect(screen.getByText(/invalid email/i)).toBeInTheDocument();
246
});
247
```
248
249
### Hover Interactions
250
```typescript
251
test('shows tooltip on hover', () => {
252
render(<Button tooltip="Click me" />);
253
254
const button = screen.getByRole('button');
255
256
fireEvent.mouseEnter(button);
257
expect(screen.getByRole('tooltip')).toHaveTextContent('Click me');
258
259
fireEvent.mouseLeave(button);
260
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
261
});
262
```
263
264
## React-Specific Event Behaviors
265
266
React Testing Library enhances certain events with React-specific behavior:
267
268
### mouseEnter / mouseLeave
269
270
In React, `mouseEnter` and `mouseLeave` are tracked by native `mouseOver` and `mouseOut` events. fireEvent automatically fires both:
271
272
```typescript { .api }
273
// Fires both mouseEnter and mouseOver
274
fireEvent.mouseEnter(element);
275
276
// Fires both mouseLeave and mouseOut
277
fireEvent.mouseLeave(element);
278
```
279
280
### pointerEnter / pointerLeave
281
282
Similar to mouse events, pointer enter/leave events fire both the synthetic and native events:
283
284
```typescript { .api }
285
// Fires both pointerEnter and pointerOver
286
fireEvent.pointerEnter(element);
287
288
// Fires both pointerLeave and pointerOut
289
fireEvent.pointerLeave(element);
290
```
291
292
### select Event
293
294
React's select event requires the element to be focused and fires a keyUp event:
295
296
```typescript { .api }
297
// Fires select, focuses element, then fires keyUp
298
fireEvent.select(element);
299
```
300
301
### focus / blur Events
302
303
React tracks native focusin/focusout events for focus/blur handlers:
304
305
```typescript { .api }
306
// Fires focusIn then focus
307
fireEvent.focus(element);
308
309
// Fires focusOut then blur
310
fireEvent.blur(element);
311
```
312
313
## Event Options
314
315
All event methods accept an optional options object with event-specific properties:
316
317
### MouseEventInit
318
```typescript { .api }
319
interface MouseEventInit {
320
altKey?: boolean;
321
button?: number; // 0=left, 1=middle, 2=right
322
buttons?: number;
323
clientX?: number;
324
clientY?: number;
325
ctrlKey?: boolean;
326
metaKey?: boolean;
327
relatedTarget?: EventTarget | null;
328
screenX?: number;
329
screenY?: number;
330
shiftKey?: boolean;
331
}
332
```
333
334
**Example:**
335
```typescript
336
fireEvent.click(element, {
337
ctrlKey: true,
338
shiftKey: true,
339
button: 0,
340
});
341
```
342
343
### KeyboardEventInit
344
```typescript { .api }
345
interface KeyboardEventInit {
346
key?: string; // 'Enter', 'Escape', 'a', etc.
347
code?: string; // 'Enter', 'Escape', 'KeyA', etc.
348
altKey?: boolean;
349
ctrlKey?: boolean;
350
metaKey?: boolean;
351
shiftKey?: boolean;
352
repeat?: boolean;
353
}
354
```
355
356
**Example:**
357
```typescript
358
fireEvent.keyDown(element, {
359
key: 'Enter',
360
code: 'Enter',
361
ctrlKey: false,
362
});
363
```
364
365
### InputEventInit
366
```typescript { .api }
367
interface InputEventInit {
368
data?: string | null;
369
inputType?: string;
370
}
371
```
372
373
### FocusEventInit
374
```typescript { .api }
375
interface FocusEventInit {
376
relatedTarget?: EventTarget | null;
377
}
378
```
379
380
### Common Keys
381
```typescript
382
// Special keys
383
{ key: 'Enter', code: 'Enter' }
384
{ key: 'Escape', code: 'Escape' }
385
{ key: 'Tab', code: 'Tab' }
386
{ key: 'ArrowDown', code: 'ArrowDown' }
387
{ key: 'ArrowUp', code: 'ArrowUp' }
388
{ key: 'ArrowLeft', code: 'ArrowLeft' }
389
{ key: 'ArrowRight', code: 'ArrowRight' }
390
{ key: 'Backspace', code: 'Backspace' }
391
{ key: 'Delete', code: 'Delete' }
392
393
// Letter keys
394
{ key: 'a', code: 'KeyA' }
395
{ key: 'A', code: 'KeyA', shiftKey: true }
396
```
397
398
## Important Notes
399
400
### Automatic act() Wrapping
401
402
All fireEvent calls are automatically wrapped in React's `act()` function, ensuring state updates are flushed before assertions:
403
404
```typescript
405
// No need to manually wrap in act()
406
fireEvent.click(button);
407
expect(screen.getByText('Updated')).toBeInTheDocument();
408
```
409
410
### Synthetic Events vs Native Events
411
412
React uses a synthetic event system. fireEvent fires native DOM events which are then processed by React's event system, matching how real browser events work.
413
414
### Event Bubbling
415
416
Events fired with fireEvent bubble through the DOM tree like real browser events:
417
418
```typescript
419
render(
420
<div onClick={() => console.log('Div clicked')}>
421
<button onClick={() => console.log('Button clicked')}>Click</button>
422
</div>
423
);
424
425
const button = screen.getByRole('button');
426
fireEvent.click(button);
427
// Logs: "Button clicked"
428
// Then logs: "Div clicked"
429
```
430
431
### User Event Alternative
432
433
For more realistic user interactions, consider using `@testing-library/user-event` which simulates complete user interactions (e.g., typing includes keydown, keypress, input, keyup events). However, `fireEvent` is simpler and sufficient for most cases.
434
435
```typescript
436
// fireEvent - simple, fast
437
fireEvent.change(input, { target: { value: 'hello' } });
438
439
// userEvent - more realistic (requires separate package)
440
import userEvent from '@testing-library/user-event';
441
await userEvent.type(input, 'hello');
442
```
443
444
## Testing Complex Interactions
445
446
### Multi-Step Form
447
```typescript
448
test('completes multi-step form', () => {
449
render(<WizardForm />);
450
451
// Step 1
452
fireEvent.change(screen.getByLabelText(/name/i), {
453
target: { value: 'John' }
454
});
455
fireEvent.click(screen.getByRole('button', { name: /next/i }));
456
457
// Step 2
458
fireEvent.change(screen.getByLabelText(/email/i), {
459
target: { value: 'john@example.com' }
460
});
461
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
462
463
expect(screen.getByText(/success/i)).toBeInTheDocument();
464
});
465
```
466
467
### Drag and Drop
468
```typescript
469
test('reorders items with drag and drop', () => {
470
render(<DragList />);
471
472
const item = screen.getByText('Item 1');
473
474
fireEvent.dragStart(item);
475
fireEvent.dragEnter(screen.getByText('Item 3'));
476
fireEvent.drop(screen.getByText('Item 3'));
477
fireEvent.dragEnd(item);
478
479
const items = screen.getAllByRole('listitem');
480
expect(items[2]).toHaveTextContent('Item 1');
481
});
482
```
483
484
## Alternative: user-event
485
486
For more realistic interactions, consider `@testing-library/user-event` (separate package):
487
488
```typescript
489
import userEvent from '@testing-library/user-event';
490
491
// More realistic typing (includes keyDown, keyPress, input, keyUp)
492
await userEvent.type(input, 'Hello');
493
494
// Realistic clicking (includes mouseDown, mouseUp, click)
495
await userEvent.click(button);
496
```
497
498
**When to use fireEvent:**
499
- Simpler, faster tests
500
- Testing specific event handlers
501
- Legacy codebase
502
503
**When to use user-event:**
504
- More realistic user behavior
505
- Testing complex interactions
506
- Accessibility testing
507