or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-testing.mdasync.mdcomponent-rendering.mdconfiguration.mdelement-queries.mdevent-simulation.mdevents.mdhook-testing.mdhooks.mdindex.mdqueries.mdquick-reference.mdrendering.md

event-simulation.mddocs/

0

# Event Simulation

1

2

React-aware event firing with proper event bubbling and React synthetic event handling. React Testing Library enhances DOM Testing Library's `fireEvent` with React-specific behavior for certain events.

3

4

## Capabilities

5

6

### FireEvent Object

7

8

The main event simulation utility that provides methods for triggering various DOM events with React-specific enhancements.

9

10

```typescript { .api }

11

/**

12

* Fire a DOM event on an element

13

* @param element - Target element

14

* @param event - Event object to fire

15

* @returns Boolean indicating if event was cancelled

16

*/

17

const fireEvent: {

18

(element: Element, event: Event): boolean;

19

20

// Mouse Events

21

click(element: Element, eventProperties?: MouseEventInit): boolean;

22

dblClick(element: Element, eventProperties?: MouseEventInit): boolean;

23

mouseDown(element: Element, eventProperties?: MouseEventInit): boolean;

24

mouseUp(element: Element, eventProperties?: MouseEventInit): boolean;

25

mouseMove(element: Element, eventProperties?: MouseEventInit): boolean;

26

mouseEnter(element: Element, eventProperties?: MouseEventInit): boolean;

27

mouseLeave(element: Element, eventProperties?: MouseEventInit): boolean;

28

mouseOver(element: Element, eventProperties?: MouseEventInit): boolean;

29

mouseOut(element: Element, eventProperties?: MouseEventInit): boolean;

30

31

// Keyboard Events

32

keyDown(element: Element, eventProperties?: KeyboardEventInit): boolean;

33

keyUp(element: Element, eventProperties?: KeyboardEventInit): boolean;

34

keyPress(element: Element, eventProperties?: KeyboardEventInit): boolean;

35

36

// Form Events

37

change(element: Element, eventProperties?: {target: {value: any}}): boolean;

38

input(element: Element, eventProperties?: {target: {value: any}}): boolean;

39

submit(element: Element, eventProperties?: Event): boolean;

40

reset(element: Element, eventProperties?: Event): boolean;

41

42

// Focus Events

43

focus(element: Element, eventProperties?: FocusEventInit): boolean;

44

blur(element: Element, eventProperties?: FocusEventInit): boolean;

45

focusIn(element: Element, eventProperties?: FocusEventInit): boolean;

46

focusOut(element: Element, eventProperties?: FocusEventInit): boolean;

47

48

// Selection Events

49

select(element: Element, eventProperties?: Event): boolean;

50

51

// Touch Events

52

touchStart(element: Element, eventProperties?: TouchEventInit): boolean;

53

touchMove(element: Element, eventProperties?: TouchEventInit): boolean;

54

touchEnd(element: Element, eventProperties?: TouchEventInit): boolean;

55

56

// Pointer Events

57

pointerDown(element: Element, eventProperties?: PointerEventInit): boolean;

58

pointerUp(element: Element, eventProperties?: PointerEventInit): boolean;

59

pointerMove(element: Element, eventProperties?: PointerEventInit): boolean;

60

pointerEnter(element: Element, eventProperties?: PointerEventInit): boolean;

61

pointerLeave(element: Element, eventProperties?: PointerEventInit): boolean;

62

pointerOver(element: Element, eventProperties?: PointerEventInit): boolean;

63

pointerOut(element: Element, eventProperties?: PointerEventInit): boolean;

64

65

// Drag Events

66

drag(element: Element, eventProperties?: DragEventInit): boolean;

67

dragEnd(element: Element, eventProperties?: DragEventInit): boolean;

68

dragEnter(element: Element, eventProperties?: DragEventInit): boolean;

69

dragExit(element: Element, eventProperties?: DragEventInit): boolean;

70

dragLeave(element: Element, eventProperties?: DragEventInit): boolean;

71

dragOver(element: Element, eventProperties?: DragEventInit): boolean;

72

dragStart(element: Element, eventProperties?: DragEventInit): boolean;

73

drop(element: Element, eventProperties?: DragEventInit): boolean;

74

};

75

```

76

77

## React-Specific Enhancements

78

79

React Testing Library provides enhanced behavior for certain events to match React's event system.

80

81

### Enhanced Mouse Events

82

83

```typescript { .api }

84

/**

85

* Enhanced mouseEnter - also fires mouseOver for React event handling

86

*/

87

fireEvent.mouseEnter(element: Element, eventProperties?: MouseEventInit): boolean;

88

89

/**

90

* Enhanced mouseLeave - also fires mouseOut for React event handling

91

*/

92

fireEvent.mouseLeave(element: Element, eventProperties?: MouseEventInit): boolean;

93

```

94

95

**Usage Examples:**

96

97

```typescript

98

function HoverComponent() {

99

const [isHovered, setIsHovered] = useState(false);

100

101

return (

102

<div

103

onMouseEnter={() => setIsHovered(true)}

104

onMouseLeave={() => setIsHovered(false)}

105

data-testid="hover-target"

106

>

107

{isHovered ? 'Hovered!' : 'Not hovered'}

108

</div>

109

);

110

}

111

112

render(<HoverComponent />);

113

114

const element = screen.getByTestId('hover-target');

115

116

// Test mouse enter (fires both mouseEnter and mouseOver)

117

fireEvent.mouseEnter(element);

118

expect(screen.getByText('Hovered!')).toBeInTheDocument();

119

120

// Test mouse leave (fires both mouseLeave and mouseOut)

121

fireEvent.mouseLeave(element);

122

expect(screen.getByText('Not hovered')).toBeInTheDocument();

123

```

124

125

### Enhanced Pointer Events

126

127

```typescript { .api }

128

/**

129

* Enhanced pointerEnter - also fires pointerOver for React event handling

130

*/

131

fireEvent.pointerEnter(element: Element, eventProperties?: PointerEventInit): boolean;

132

133

/**

134

* Enhanced pointerLeave - also fires pointerOut for React event handling

135

*/

136

fireEvent.pointerLeave(element: Element, eventProperties?: PointerEventInit): boolean;

137

```

138

139

### Enhanced Focus Events

140

141

```typescript { .api }

142

/**

143

* Enhanced focus - also fires focusIn for React event handling

144

*/

145

fireEvent.focus(element: Element, eventProperties?: FocusEventInit): boolean;

146

147

/**

148

* Enhanced blur - also fires focusOut for React event handling

149

*/

150

fireEvent.blur(element: Element, eventProperties?: FocusEventInit): boolean;

151

```

152

153

**Usage Examples:**

154

155

```typescript

156

function FocusComponent() {

157

const [focused, setFocused] = useState(false);

158

159

return (

160

<input

161

onFocus={() => setFocused(true)}

162

onBlur={() => setFocused(false)}

163

placeholder={focused ? 'Focused!' : 'Not focused'}

164

data-testid="focus-input"

165

/>

166

);

167

}

168

169

render(<FocusComponent />);

170

171

const input = screen.getByTestId('focus-input');

172

173

// Test focus (fires both focus and focusIn)

174

fireEvent.focus(input);

175

expect(input).toHaveAttribute('placeholder', 'Focused!');

176

177

// Test blur (fires both blur and focusOut)

178

fireEvent.blur(input);

179

expect(input).toHaveAttribute('placeholder', 'Not focused');

180

```

181

182

### Enhanced Select Event

183

184

```typescript { .api }

185

/**

186

* Enhanced select - focuses element and fires keyUp for React event handling

187

*/

188

fireEvent.select(element: Element, eventProperties?: Event): boolean;

189

```

190

191

**Usage Examples:**

192

193

```typescript

194

function SelectableInput() {

195

const [selected, setSelected] = useState(false);

196

197

return (

198

<input

199

onSelect={() => setSelected(true)}

200

defaultValue="Selectable text"

201

data-testid="selectable-input"

202

/>

203

);

204

}

205

206

render(<SelectableInput />);

207

208

const input = screen.getByTestId('selectable-input');

209

210

// Enhanced select event focuses and triggers selection

211

fireEvent.select(input);

212

213

// Input should be focused after select

214

expect(input).toHaveFocus();

215

```

216

217

## Common Event Patterns

218

219

### Form Interactions

220

221

```typescript

222

function LoginForm() {

223

const [credentials, setCredentials] = useState({ username: '', password: '' });

224

const [submitted, setSubmitted] = useState(false);

225

226

const handleSubmit = (e) => {

227

e.preventDefault();

228

setSubmitted(true);

229

};

230

231

return (

232

<form onSubmit={handleSubmit}>

233

<input

234

placeholder="Username"

235

value={credentials.username}

236

onChange={(e) => setCredentials(prev => ({ ...prev, username: e.target.value }))}

237

data-testid="username"

238

/>

239

<input

240

type="password"

241

placeholder="Password"

242

value={credentials.password}

243

onChange={(e) => setCredentials(prev => ({ ...prev, password: e.target.value }))}

244

data-testid="password"

245

/>

246

<button type="submit">Login</button>

247

{submitted && <p>Form submitted!</p>}

248

</form>

249

);

250

}

251

252

render(<LoginForm />);

253

254

const usernameInput = screen.getByTestId('username');

255

const passwordInput = screen.getByTestId('password');

256

const submitButton = screen.getByText('Login');

257

258

// Type in username

259

fireEvent.change(usernameInput, { target: { value: 'testuser' } });

260

expect(usernameInput).toHaveValue('testuser');

261

262

// Type in password

263

fireEvent.change(passwordInput, { target: { value: 'password123' } });

264

expect(passwordInput).toHaveValue('password123');

265

266

// Submit form

267

fireEvent.click(submitButton);

268

expect(screen.getByText('Form submitted!')).toBeInTheDocument();

269

270

// Alternative: submit via form

271

fireEvent.submit(screen.getByRole('form'));

272

```

273

274

### Keyboard Interactions

275

276

```typescript

277

function KeyboardComponent() {

278

const [keys, setKeys] = useState([]);

279

280

const handleKeyDown = (e) => {

281

setKeys(prev => [...prev, e.key]);

282

};

283

284

return (

285

<div>

286

<input onKeyDown={handleKeyDown} data-testid="keyboard-input" />

287

<ul>

288

{keys.map((key, index) => (

289

<li key={index}>{key}</li>

290

))}

291

</ul>

292

</div>

293

);

294

}

295

296

render(<KeyboardComponent />);

297

298

const input = screen.getByTestId('keyboard-input');

299

300

// Type individual keys

301

fireEvent.keyDown(input, { key: 'H', code: 'KeyH' });

302

fireEvent.keyDown(input, { key: 'i', code: 'KeyI' });

303

fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });

304

305

// Check keys were registered

306

expect(screen.getByText('H')).toBeInTheDocument();

307

expect(screen.getByText('i')).toBeInTheDocument();

308

expect(screen.getByText('Enter')).toBeInTheDocument();

309

310

// Special keys

311

fireEvent.keyDown(input, { key: 'Escape', code: 'Escape' });

312

fireEvent.keyDown(input, { key: 'Tab', code: 'Tab', shiftKey: true });

313

```

314

315

### Mouse Interactions

316

317

```typescript

318

function ClickCounter() {

319

const [clicks, setClicks] = useState(0);

320

const [position, setPosition] = useState({ x: 0, y: 0 });

321

322

const handleClick = (e) => {

323

setClicks(prev => prev + 1);

324

setPosition({ x: e.clientX, y: e.clientY });

325

};

326

327

const handleDoubleClick = () => {

328

setClicks(0);

329

};

330

331

return (

332

<div

333

onClick={handleClick}

334

onDoubleClick={handleDoubleClick}

335

style={{ width: 200, height: 200, border: '1px solid black' }}

336

data-testid="click-area"

337

>

338

Clicks: {clicks}

339

<br />

340

Position: {position.x}, {position.y}

341

</div>

342

);

343

}

344

345

render(<ClickCounter />);

346

347

const clickArea = screen.getByTestId('click-area');

348

349

// Single click with position

350

fireEvent.click(clickArea, { clientX: 100, clientY: 50 });

351

expect(screen.getByText(/Clicks: 1/)).toBeInTheDocument();

352

expect(screen.getByText(/Position: 100, 50/)).toBeInTheDocument();

353

354

// Another click

355

fireEvent.click(clickArea, { clientX: 150, clientY: 75 });

356

expect(screen.getByText(/Clicks: 2/)).toBeInTheDocument();

357

358

// Double click to reset

359

fireEvent.dblClick(clickArea);

360

expect(screen.getByText(/Clicks: 0/)).toBeInTheDocument();

361

362

// Mouse button variations

363

fireEvent.click(clickArea, { button: 1 }); // Middle click

364

fireEvent.click(clickArea, { button: 2 }); // Right click

365

```

366

367

### Drag and Drop

368

369

```typescript

370

function DragDropComponent() {

371

const [dragData, setDragData] = useState('');

372

const [dropped, setDropped] = useState(false);

373

374

const handleDragStart = (e) => {

375

e.dataTransfer.setData('text/plain', 'dragged data');

376

};

377

378

const handleDrop = (e) => {

379

e.preventDefault();

380

const data = e.dataTransfer.getData('text/plain');

381

setDragData(data);

382

setDropped(true);

383

};

384

385

const handleDragOver = (e) => {

386

e.preventDefault();

387

};

388

389

return (

390

<div>

391

<div

392

draggable

393

onDragStart={handleDragStart}

394

data-testid="drag-source"

395

style={{ padding: 20, background: 'lightblue' }}

396

>

397

Drag me

398

</div>

399

<div

400

onDrop={handleDrop}

401

onDragOver={handleDragOver}

402

data-testid="drop-target"

403

style={{ padding: 20, background: 'lightgreen', marginTop: 10 }}

404

>

405

Drop here

406

{dropped && <p>Dropped: {dragData}</p>}

407

</div>

408

</div>

409

);

410

}

411

412

render(<DragDropComponent />);

413

414

const dragSource = screen.getByTestId('drag-source');

415

const dropTarget = screen.getByTestId('drop-target');

416

417

// Start drag

418

const dragStartEvent = new DragEvent('dragstart', {

419

bubbles: true,

420

cancelable: true,

421

dataTransfer: new DataTransfer()

422

});

423

dragStartEvent.dataTransfer.setData = jest.fn();

424

425

fireEvent(dragSource, dragStartEvent);

426

427

// Drag over target

428

fireEvent.dragOver(dropTarget);

429

430

// Drop

431

const dropEvent = new DragEvent('drop', {

432

bubbles: true,

433

cancelable: true,

434

dataTransfer: new DataTransfer()

435

});

436

dropEvent.dataTransfer.getData = jest.fn(() => 'dragged data');

437

438

fireEvent(dropTarget, dropEvent);

439

440

expect(screen.getByText('Dropped: dragged data')).toBeInTheDocument();

441

```

442

443

### Touch Events

444

445

```typescript

446

function TouchComponent() {

447

const [touches, setTouches] = useState([]);

448

449

const handleTouch = (e) => {

450

const touchList = Array.from(e.touches).map(touch => ({

451

x: touch.clientX,

452

y: touch.clientY

453

}));

454

setTouches(touchList);

455

};

456

457

return (

458

<div

459

onTouchStart={handleTouch}

460

onTouchMove={handleTouch}

461

onTouchEnd={() => setTouches([])}

462

data-testid="touch-area"

463

style={{ width: 200, height: 200, background: 'lightgray' }}

464

>

465

Touches: {touches.length}

466

{touches.map((touch, index) => (

467

<div key={index}>Touch {index}: {touch.x}, {touch.y}</div>

468

))}

469

</div>

470

);

471

}

472

473

render(<TouchComponent />);

474

475

const touchArea = screen.getByTestId('touch-area');

476

477

// Single touch

478

fireEvent.touchStart(touchArea, {

479

touches: [{ clientX: 100, clientY: 100 }]

480

});

481

expect(screen.getByText('Touches: 1')).toBeInTheDocument();

482

483

// Multi-touch

484

fireEvent.touchStart(touchArea, {

485

touches: [

486

{ clientX: 50, clientY: 50 },

487

{ clientX: 150, clientY: 150 }

488

]

489

});

490

expect(screen.getByText('Touches: 2')).toBeInTheDocument();

491

492

// End touches

493

fireEvent.touchEnd(touchArea);

494

expect(screen.getByText('Touches: 0')).toBeInTheDocument();

495

```

496

497

### Custom Events

498

499

```typescript

500

function CustomEventComponent() {

501

const [customData, setCustomData] = useState('');

502

503

useEffect(() => {

504

const handleCustomEvent = (e) => {

505

setCustomData(e.detail.message);

506

};

507

508

document.addEventListener('customEvent', handleCustomEvent);

509

return () => document.removeEventListener('customEvent', handleCustomEvent);

510

}, []);

511

512

return <div>Custom data: {customData}</div>;

513

}

514

515

render(<CustomEventComponent />);

516

517

// Fire custom event

518

const customEvent = new CustomEvent('customEvent', {

519

detail: { message: 'Hello from custom event!' }

520

});

521

522

fireEvent(document, customEvent);

523

524

expect(screen.getByText('Custom data: Hello from custom event!')).toBeInTheDocument();

525

```