or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

css-fixtures.mdevent-spying.mdhtml-fixtures.mdindex.mdjquery-matchers.mdjson-fixtures.md
tile.json

event-spying.mddocs/

0

# Event Spying

1

2

Comprehensive event spy system for testing jQuery event triggers, with support for event prevention, propagation control, and detailed event inspection. Essential for testing event-driven jQuery applications and components.

3

4

## Capabilities

5

6

### Global Event Spy Function

7

8

#### spyOnEvent

9

10

Creates an event spy for specified selector and event type.

11

12

```javascript { .api }

13

/**

14

* Creates an event spy for given selector and event type

15

* Returns spy object with call tracking and control methods

16

* @param selector - CSS selector or jQuery element to spy on

17

* @param eventName - Event type to spy on (e.g., 'click', 'submit', 'custom-event')

18

* @returns EventSpy object with tracking and control methods

19

*/

20

function spyOnEvent(selector, eventName);

21

```

22

23

**Usage Examples:**

24

```javascript

25

// Basic event spying

26

var clickSpy = spyOnEvent('#button', 'click');

27

$('#button').click();

28

expect(clickSpy).toHaveBeenTriggered();

29

30

// Spy on custom events

31

var customSpy = spyOnEvent('.widget', 'widget-updated');

32

$('.widget').trigger('widget-updated', {data: 'test'});

33

expect(customSpy).toHaveBeenTriggered();

34

35

// Spy on multiple events

36

var submitSpy = spyOnEvent('#form', 'submit');

37

var focusSpy = spyOnEvent('#input', 'focus');

38

```

39

40

### Event Spy Object

41

42

The spy object returned by `spyOnEvent()` provides tracking and control:

43

44

```javascript { .api }

45

/**

46

* Event spy object with tracking capabilities

47

*/

48

interface EventSpy {

49

/** CSS selector being spied on */

50

selector: string;

51

52

/** Event name being spied on */

53

eventName: string;

54

55

/** Internal event handler function */

56

handler: Function;

57

58

/** Reset spy state (clear call count and arguments) */

59

reset(): void;

60

61

/** Call tracking information */

62

calls: {

63

/** Number of times event was triggered */

64

count(): number;

65

66

/** Whether event was triggered at least once */

67

any(): boolean;

68

};

69

}

70

```

71

72

**Spy Object Usage:**

73

```javascript

74

var spy = spyOnEvent('#element', 'click');

75

76

// Trigger events

77

$('#element').click();

78

$('#element').click();

79

80

// Check call information

81

expect(spy.calls.count()).toBe(2);

82

expect(spy.calls.any()).toBe(true);

83

84

// Reset spy state

85

spy.reset();

86

expect(spy.calls.count()).toBe(0);

87

expect(spy.calls.any()).toBe(false);

88

```

89

90

### Event Spy Matchers

91

92

#### toHaveBeenTriggered

93

94

Checks if spied event was triggered (using spy object).

95

96

```javascript { .api }

97

/**

98

* Checks if event spy was triggered at least once

99

* Use with spy object returned by spyOnEvent()

100

*/

101

expect(eventSpy).toHaveBeenTriggered();

102

```

103

104

#### toHaveBeenTriggeredOn

105

106

Checks if event was triggered on specific selector (using event name).

107

108

```javascript { .api }

109

/**

110

* Checks if event was triggered on the specified selector

111

* Use with event name string and selector

112

* @param selector - CSS selector to check

113

*/

114

expect(eventName).toHaveBeenTriggeredOn(selector);

115

```

116

117

**Trigger Matcher Examples:**

118

```javascript

119

// Using spy object

120

var clickSpy = spyOnEvent('#button', 'click');

121

$('#button').click();

122

expect(clickSpy).toHaveBeenTriggered();

123

expect(clickSpy).not.toHaveBeenTriggered(); // After reset

124

125

// Using event name and selector

126

$('#link').click();

127

expect('click').toHaveBeenTriggeredOn('#link');

128

expect('hover').not.toHaveBeenTriggeredOn('#link');

129

```

130

131

#### toHaveBeenTriggeredOnAndWith

132

133

Checks if event was triggered with specific arguments.

134

135

```javascript { .api }

136

/**

137

* Checks if event was triggered on selector with specific arguments

138

* @param selector - CSS selector to check

139

* @param expectedArgs - Expected event arguments (array or single value)

140

*/

141

expect(eventName).toHaveBeenTriggeredOnAndWith(selector, expectedArgs);

142

```

143

144

**Usage Example:**

145

```javascript

146

spyOnEvent('#widget', 'data-updated');

147

148

// Trigger with custom data

149

$('#widget').trigger('data-updated', [{id: 123, name: 'test'}]);

150

151

// Check trigger with arguments

152

expect('data-updated').toHaveBeenTriggeredOnAndWith('#widget', [{id: 123, name: 'test'}]);

153

```

154

155

### Event Prevention and Propagation

156

157

#### toHaveBeenPrevented

158

159

Checks if spied event was prevented (using spy object).

160

161

```javascript { .api }

162

/**

163

* Checks if event's default action was prevented

164

* Use with spy object returned by spyOnEvent()

165

*/

166

expect(eventSpy).toHaveBeenPrevented();

167

```

168

169

#### toHaveBeenPreventedOn

170

171

Checks if event was prevented on specific selector (using event name).

172

173

```javascript { .api }

174

/**

175

* Checks if event's default action was prevented on selector

176

* @param selector - CSS selector to check

177

*/

178

expect(eventName).toHaveBeenPreventedOn(selector);

179

```

180

181

**Prevention Examples:**

182

```javascript

183

// Set up prevention

184

$('#form').on('submit', function(e) {

185

e.preventDefault();

186

});

187

188

var submitSpy = spyOnEvent('#form', 'submit');

189

$('#form').submit();

190

191

// Check prevention with spy object

192

expect(submitSpy).toHaveBeenPrevented();

193

194

// Check prevention with event name

195

expect('submit').toHaveBeenPreventedOn('#form');

196

```

197

198

#### toHaveBeenStopped

199

200

Checks if spied event propagation was stopped (using spy object).

201

202

```javascript { .api }

203

/**

204

* Checks if event propagation was stopped

205

* Use with spy object returned by spyOnEvent()

206

*/

207

expect(eventSpy).toHaveBeenStopped();

208

```

209

210

#### toHaveBeenStoppedOn

211

212

Checks if event propagation was stopped on specific selector (using event name).

213

214

```javascript { .api }

215

/**

216

* Checks if event propagation was stopped on selector

217

* @param selector - CSS selector to check

218

*/

219

expect(eventName).toHaveBeenStoppedOn(selector);

220

```

221

222

**Propagation Examples:**

223

```javascript

224

// Set up propagation stopping

225

$('.inner').on('click', function(e) {

226

e.stopPropagation();

227

});

228

229

var clickSpy = spyOnEvent('.inner', 'click');

230

$('.inner').click();

231

232

// Check propagation stopping

233

expect(clickSpy).toHaveBeenStopped();

234

expect('click').toHaveBeenStoppedOn('.inner');

235

```

236

237

### Advanced Event Spying Patterns

238

239

#### Multiple Event Types

240

```javascript

241

describe('Multi-event component', function() {

242

var clickSpy, hoverSpy, customSpy;

243

244

beforeEach(function() {

245

loadFixtures('<div id="widget">Widget</div>');

246

clickSpy = spyOnEvent('#widget', 'click');

247

hoverSpy = spyOnEvent('#widget', 'mouseenter');

248

customSpy = spyOnEvent('#widget', 'widget-activated');

249

});

250

251

it('should handle multiple event types', function() {

252

$('#widget').click().trigger('mouseenter').trigger('widget-activated');

253

254

expect(clickSpy).toHaveBeenTriggered();

255

expect(hoverSpy).toHaveBeenTriggered();

256

expect(customSpy).toHaveBeenTriggered();

257

});

258

});

259

```

260

261

#### Event Sequence Testing

262

```javascript

263

it('should trigger events in correct sequence', function() {

264

var focusSpy = spyOnEvent('#input', 'focus');

265

var changeSpy = spyOnEvent('#input', 'change');

266

var blurSpy = spyOnEvent('#input', 'blur');

267

268

// Simulate user interaction sequence

269

$('#input').focus().val('test value').change().blur();

270

271

expect(focusSpy.calls.count()).toBe(1);

272

expect(changeSpy.calls.count()).toBe(1);

273

expect(blurSpy.calls.count()).toBe(1);

274

});

275

```

276

277

#### Complex Event Data Testing

278

```javascript

279

it('should pass correct data with custom events', function() {

280

spyOnEvent('#component', 'data-loaded');

281

282

var testData = {

283

users: [{id: 1, name: 'Alice'}],

284

timestamp: Date.now()

285

};

286

287

$('#component').trigger('data-loaded', [testData]);

288

289

expect('data-loaded').toHaveBeenTriggeredOnAndWith('#component', [testData]);

290

});

291

```

292

293

#### Event Delegation Testing

294

```javascript

295

describe('Event delegation', function() {

296

beforeEach(function() {

297

setFixtures(`

298

<ul id="list">

299

<li class="item">Item 1</li>

300

<li class="item">Item 2</li>

301

</ul>

302

`);

303

304

// Set up delegated event handler

305

$('#list').on('click', '.item', function(e) {

306

$(this).addClass('clicked');

307

});

308

});

309

310

it('should handle delegated events', function() {

311

var clickSpy = spyOnEvent('.item', 'click');

312

313

$('.item').first().click();

314

315

expect(clickSpy).toHaveBeenTriggered();

316

expect($('.item').first()).toHaveClass('clicked');

317

});

318

});

319

```

320

321

### Event Spy Lifecycle

322

323

#### Automatic Cleanup

324

Event spies are automatically cleaned up between tests:

325

326

```javascript

327

// Automatic cleanup happens in afterEach

328

afterEach(function() {

329

jasmine.jQuery.events.cleanUp(); // Called automatically

330

});

331

```

332

333

#### Manual Spy Management

334

```javascript

335

describe('Manual spy management', function() {

336

var spy;

337

338

beforeEach(function() {

339

spy = spyOnEvent('#element', 'click');

340

});

341

342

it('should reset spy between tests', function() {

343

$('#element').click();

344

expect(spy.calls.count()).toBe(1);

345

346

// Reset manually if needed mid-test

347

spy.reset();

348

expect(spy.calls.count()).toBe(0);

349

});

350

});

351

```

352

353

### Error Handling

354

355

#### Missing Event Spy Errors

356

```javascript { .api }

357

/**

358

* Error thrown when accessing spy data for non-existent spy:

359

* "There is no spy for [eventName] on [selector]. Make sure to create a spy using spyOnEvent."

360

*/

361

```

362

363

**Error Example:**

364

```javascript

365

// This will throw error - no spy created

366

try {

367

expect('click').toHaveBeenTriggeredOn('#element');

368

} catch (error) {

369

expect(error.message).toContain('There is no spy for click on #element');

370

}

371

372

// Correct usage - create spy first

373

spyOnEvent('#element', 'click');

374

$('#element').click();

375

expect('click').toHaveBeenTriggeredOn('#element'); // Works

376

```

377

378

### Integration with jQuery Event System

379

380

#### Namespace Support

381

```javascript

382

// Spy on namespaced events

383

var namespacedSpy = spyOnEvent('#element', 'click.myapp');

384

$('#element').trigger('click.myapp');

385

expect(namespacedSpy).toHaveBeenTriggered();

386

```

387

388

#### Custom Event Support

389

```javascript

390

// Spy on custom events

391

var customSpy = spyOnEvent('#widget', 'widget:updated');

392

$('#widget').trigger('widget:updated', {version: '2.0'});

393

expect(customSpy).toHaveBeenTriggered();

394

```

395

396

#### Event Object Access

397

While jasmine-jquery doesn't directly expose event objects, you can combine with standard Jasmine spies:

398

399

```javascript

400

var handler = jasmine.createSpy('clickHandler');

401

$('#element').on('click', handler);

402

403

var eventSpy = spyOnEvent('#element', 'click');

404

$('#element').click();

405

406

expect(eventSpy).toHaveBeenTriggered();

407

expect(handler).toHaveBeenCalled();

408

// Can inspect handler.calls.argsFor(0)[0] for event object

409

```

410

411

### Advanced Event System Functions

412

413

#### jasmine.jQuery.events.args

414

415

Retrieves arguments from spied event for detailed inspection.

416

417

```javascript { .api }

418

/**

419

* Gets arguments passed to spied event

420

* @param selector - CSS selector that was spied on

421

* @param eventName - Event name that was spied on

422

* @returns Array of arguments passed to event handler

423

* @throws Error if no spy exists for the selector/event combination

424

*/

425

function jasmine.jQuery.events.args(selector, eventName);

426

```

427

428

**Usage Example:**

429

```javascript

430

spyOnEvent('#form', 'submit');

431

$('#form').trigger('submit', [{data: 'test'}, 'extra-arg']);

432

433

var eventArgs = jasmine.jQuery.events.args('#form', 'submit');

434

expect(eventArgs[1]).toEqual({data: 'test'}); // First custom argument

435

expect(eventArgs[2]).toBe('extra-arg'); // Second custom argument

436

```

437

438

#### jasmine.jQuery.events.wasTriggered

439

440

Checks if event was triggered (low-level boolean check).

441

442

```javascript { .api }

443

/**

444

* Checks if event was triggered on selector (returns boolean)

445

* Low-level alternative to toHaveBeenTriggeredOn matcher

446

* @param selector - CSS selector to check

447

* @param eventName - Event name to check

448

* @returns Boolean indicating if event was triggered

449

*/

450

function jasmine.jQuery.events.wasTriggered(selector, eventName);

451

```

452

453

#### jasmine.jQuery.events.wasTriggeredWith

454

455

Checks if event was triggered with specific arguments.

456

457

```javascript { .api }

458

/**

459

* Checks if event was triggered with specific arguments

460

* @param selector - CSS selector to check

461

* @param eventName - Event name to check

462

* @param expectedArgs - Expected arguments

463

* @param util - Jasmine utility object

464

* @param customEqualityTesters - Custom equality testers array

465

* @returns Boolean indicating if event was triggered with expected arguments

466

*/

467

function jasmine.jQuery.events.wasTriggeredWith(selector, eventName, expectedArgs, util, customEqualityTesters);

468

```

469

470

#### jasmine.jQuery.events.wasPrevented

471

472

Checks if event default action was prevented (low-level boolean check).

473

474

```javascript { .api }

475

/**

476

* Checks if event's default action was prevented (returns boolean)

477

* Low-level alternative to toHaveBeenPreventedOn matcher

478

* @param selector - CSS selector to check

479

* @param eventName - Event name to check

480

* @returns Boolean indicating if event was prevented

481

*/

482

function jasmine.jQuery.events.wasPrevented(selector, eventName);

483

```

484

485

#### jasmine.jQuery.events.wasStopped

486

487

Checks if event propagation was stopped (low-level boolean check).

488

489

```javascript { .api }

490

/**

491

* Checks if event propagation was stopped (returns boolean)

492

* Low-level alternative to toHaveBeenStoppedOn matcher

493

* @param selector - CSS selector to check

494

* @param eventName - Event name to check

495

* @returns Boolean indicating if event propagation was stopped

496

*/

497

function jasmine.jQuery.events.wasStopped(selector, eventName);

498

```

499

500

#### jasmine.jQuery.events.spyOn

501

502

Creates event spy (internal method, use spyOnEvent() instead).

503

504

```javascript { .api }

505

/**

506

* Creates event spy (internal method - use global spyOnEvent() instead)

507

* @param selector - CSS selector to spy on

508

* @param eventName - Event name to spy on

509

* @returns EventSpy object

510

* @internal

511

*/

512

function jasmine.jQuery.events.spyOn(selector, eventName);

513

```

514

515

#### jasmine.jQuery.events.cleanUp

516

517

Manually cleans up all event spies (automatically called after each test).

518

519

```javascript { .api }

520

/**

521

* Manually clean up all event spies and tracked data

522

* Normally called automatically in afterEach hook

523

*/

524

function jasmine.jQuery.events.cleanUp();

525

```

526

527

#### jasmine.spiedEventsKey

528

529

Generates unique key for tracking spied events (internal utility).

530

531

```javascript { .api }

532

/**

533

* Creates unique key for spied event storage

534

* @param selector - CSS selector being spied on

535

* @param eventName - Event name being spied on

536

* @returns String key for internal event tracking

537

*/

538

function jasmine.spiedEventsKey(selector, eventName);

539

```

540

541

### Error Handling and Messages

542

543

#### Specific Error Messages

544

545

```javascript { .api }

546

/**

547

* Error thrown when accessing spy data for non-existent spy:

548

* "There is no spy for [eventName] on [selector]. Make sure to create a spy using spyOnEvent."

549

*

550

* This error occurs when calling jasmine.jQuery.events.args() or using event

551

* matchers without first creating a spy with spyOnEvent()

552

*/

553

```

554

555

### Best Practices

556

557

#### Descriptive Spy Variables

558

```javascript

559

// Good - descriptive names

560

var submitSpy = spyOnEvent('#login-form', 'submit');

561

var validationSpy = spyOnEvent('.form-field', 'validation:failed');

562

563

// Less clear

564

var spy1 = spyOnEvent('#form', 'submit');

565

var spy2 = spyOnEvent('.field', 'validation:failed');

566

```

567

568

#### Combine with Fixture Loading

569

```javascript

570

describe('Interactive component', function() {

571

beforeEach(function() {

572

loadFixtures('interactive-widget.html');

573

loadStyleFixtures('widget-styles.css');

574

});

575

576

it('should handle user interactions', function() {

577

var clickSpy = spyOnEvent('.widget-button', 'click');

578

var hoverSpy = spyOnEvent('.widget', 'mouseenter');

579

580

$('.widget').trigger('mouseenter');

581

$('.widget-button').click();

582

583

expect(hoverSpy).toHaveBeenTriggered();

584

expect(clickSpy).toHaveBeenTriggered();

585

});

586

});

587

```