0
# Events
1
2
Event-driven architecture enabling monitoring of test lifecycle, capturing results, building custom reporting solutions, and integrating with external tools.
3
4
## Capabilities
5
6
### Event Registration
7
8
Register callbacks to listen for test lifecycle events.
9
10
```javascript { .api }
11
/**
12
* Register event listener for test lifecycle events
13
* @param {string} eventName - Name of the event to listen for
14
* @param {Function} callback - Function to call when event occurs
15
*/
16
QUnit.on(eventName, callback)
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
import QUnit from "qunit";
23
24
// Listen for test start events
25
QUnit.on("testStart", function(details) {
26
console.log(`Starting test: ${details.name}`);
27
});
28
29
// Listen for assertion events
30
QUnit.on("assertion", function(details) {
31
if (!details.result) {
32
console.error(`Assertion failed: ${details.message}`);
33
}
34
});
35
36
// Listen for test completion
37
QUnit.on("testEnd", function(details) {
38
console.log(`Test completed: ${details.name} (${details.status})`);
39
});
40
```
41
42
### Test Run Events
43
44
Events related to overall test run lifecycle.
45
46
```javascript { .api }
47
/**
48
* Fired when test run begins
49
* @typedef {Object} RunStartEvent
50
* @property {number} totalTests - Total number of tests to run
51
* @property {Array} modules - Array of modules (for legacy callbacks)
52
*/
53
QUnit.on('runStart', function(runSuite) {
54
// runSuite contains test run information
55
console.log('Test run started');
56
});
57
58
/**
59
* Fired when test run completes
60
* @typedef {Object} RunEndEvent
61
* @property {string} status - 'passed' or 'failed'
62
* @property {Object} testCounts - Test result counts
63
* @property {number} runtime - Total runtime in milliseconds
64
*/
65
QUnit.on('runEnd', function(runSuite) {
66
// runSuite contains final test results
67
console.log('Test run completed');
68
});
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
QUnit.on('runStart', function(runSuite) {
75
console.log('Test run started');
76
console.log(`Total tests: ${QUnit.config.stats.testCount}`);
77
});
78
79
QUnit.on('runEnd', function(runSuite) {
80
console.log('Test run completed');
81
console.log(`Results: ${runSuite.testCounts.passed} passed, ${runSuite.testCounts.failed} failed`);
82
console.log(`Runtime: ${runSuite.runtime}ms`);
83
});
84
```
85
86
### Module Events
87
88
Events related to test module execution.
89
90
```javascript { .api }
91
/**
92
* Fired when module execution begins
93
* @typedef {Object} SuiteStartEvent
94
* @property {string} name - Module name
95
* @property {string} moduleId - Module ID
96
*/
97
QUnit.on('suiteStart', function(suite) {
98
console.log(`Starting module: ${suite.name}`);
99
});
100
101
/**
102
* Fired when module execution completes
103
* @typedef {Object} SuiteEndEvent
104
* @property {string} name - Module name
105
* @property {string} moduleId - Module ID
106
* @property {string} status - 'passed' or 'failed'
107
* @property {Object} testCounts - Test counts within module
108
* @property {number} runtime - Module runtime in milliseconds
109
*/
110
QUnit.on('suiteEnd', function(suite) {
111
console.log(`Module completed: ${suite.name}`);
112
});
113
```
114
115
**Usage Examples:**
116
117
```javascript
118
QUnit.on('suiteStart', function(suite) {
119
console.log(`Starting module: ${suite.name}`);
120
console.log(`Tests in module: ${suite.testCounts.total}`);
121
});
122
123
QUnit.on('suiteEnd', function(suite) {
124
console.log(`Module ${suite.name} completed`);
125
console.log(`Status: ${suite.status}`);
126
console.log(`Runtime: ${suite.runtime}ms`);
127
});
128
```
129
130
### Test Events
131
132
Events related to individual test execution.
133
134
```javascript { .api }
135
/**
136
* Fired when individual test begins
137
* @typedef {Object} TestStartEvent
138
* @property {string} name - Test name
139
* @property {string} testId - Test ID
140
* @property {string} module - Module name
141
* @property {boolean} [previousFailure] - Whether test failed in previous run
142
*/
143
QUnit.on('testStart', function(test) {
144
console.log(`Starting test: ${test.name}`);
145
});
146
147
/**
148
* Fired when individual test completes
149
* @typedef {Object} TestEndEvent
150
* @property {string} name - Test name
151
* @property {string} testId - Test ID
152
* @property {string} module - Module name
153
* @property {boolean} skipped - Whether test was skipped
154
* @property {boolean} todo - Whether test is a todo test
155
* @property {number} failed - Number of failed assertions
156
* @property {number} passed - Number of passed assertions
157
* @property {number} total - Total number of assertions
158
* @property {number} runtime - Test runtime in milliseconds
159
* @property {Array} assertions - Array of assertion objects (HTML Reporter use)
160
* @property {string} source - Test source location (getter)
161
*/
162
QUnit.on('testEnd', function(test) {
163
const status = test.failed > 0 ? 'failed' : 'passed';
164
console.log(`Test ${status}: ${test.name}`);
165
});
166
```
167
168
**Usage Examples:**
169
170
```javascript
171
QUnit.on('testStart', function(test) {
172
console.log(`Starting test: ${test.name}`);
173
console.log(`Module: ${test.module}`);
174
console.log(`Test ID: ${test.testId}`);
175
});
176
177
QUnit.on('testEnd', function(test) {
178
const status = test.failed > 0 ? 'FAILED' : 'PASSED';
179
console.log(`${status}: ${test.name}`);
180
console.log(` Passed: ${test.passed}, Failed: ${test.failed}, Total: ${test.total}`);
181
console.log(` Runtime: ${test.runtime}ms`);
182
183
if (test.skipped) {
184
console.log(' Status: SKIPPED');
185
} else if (test.todo) {
186
console.log(' Status: TODO');
187
}
188
});
189
```
190
191
### Assertion Events
192
193
Events fired for each individual assertion.
194
195
```javascript { .api }
196
/**
197
* Fired for each assertion
198
* @typedef {Object} AssertionEvent
199
* @property {boolean} passed - Whether assertion passed
200
* @property {any} [actual] - Actual value
201
* @property {any} [expected] - Expected value
202
* @property {string} message - Assertion message
203
* @property {string} [stack] - Stack trace for failed assertions
204
* @property {boolean} todo - Whether assertion is in a todo test
205
*/
206
QUnit.on('assertion', function(assertion) {
207
if (assertion.passed) {
208
console.log(`✓ ${assertion.message}`);
209
} else {
210
console.error(`✗ ${assertion.message}`);
211
if (assertion.stack) {
212
console.error(assertion.stack);
213
}
214
}
215
});
216
```
217
218
**Usage Examples:**
219
220
```javascript
221
QUnit.on('assertion', function(assertion) {
222
if (assertion.passed) {
223
console.log(`✓ ${assertion.message}`);
224
} else {
225
console.error(`✗ ${assertion.message}`);
226
227
if (assertion.actual !== undefined) {
228
console.error(` Expected: ${assertion.expected}`);
229
console.error(` Actual: ${assertion.actual}`);
230
}
231
232
if (assertion.stack) {
233
console.error(` ${assertion.stack}`);
234
}
235
}
236
});
237
```
238
239
### Error Events
240
241
Events fired for uncaught errors and exceptions.
242
243
```javascript { .api }
244
/**
245
* Fired for uncaught errors during test execution
246
* @typedef {Object} ErrorEvent
247
* @property {string} message - Error message
248
* @property {string} [source] - Error source location
249
* @property {string} [testName] - Test name when error occurred
250
* @property {string} [module] - Module name when error occurred
251
*/
252
QUnit.on('error', function(error) {
253
console.error('Uncaught error:', error.message);
254
if (error.source) {
255
console.error('Source:', error.source);
256
}
257
});
258
```
259
260
**Usage Examples:**
261
262
```javascript
263
QUnit.on("error", function(details) {
264
console.error("Uncaught error during test execution:");
265
console.error(`Message: ${details.message}`);
266
console.error(`Source: ${details.source}`);
267
268
if (details.testName) {
269
console.error(`Test: ${details.testName}`);
270
}
271
272
if (details.module) {
273
console.error(`Module: ${details.module}`);
274
}
275
});
276
```
277
278
### Custom Reporter Implementation
279
280
Build custom reporters using the event system.
281
282
**Usage Examples:**
283
284
```javascript
285
// Custom JSON reporter
286
class JSONReporter {
287
constructor() {
288
this.results = {
289
tests: [],
290
modules: [],
291
summary: null
292
};
293
294
this.bindEvents();
295
}
296
297
bindEvents() {
298
QUnit.on("testEnd", (details) => {
299
this.results.tests.push({
300
name: details.name,
301
module: details.module,
302
status: details.status,
303
assertions: details.assertions.total,
304
runtime: details.runtime,
305
errors: details.errors
306
});
307
});
308
309
QUnit.on("suiteEnd", (details) => {
310
this.results.modules.push({
311
name: details.name,
312
status: details.status,
313
testCounts: details.testCounts,
314
runtime: details.runtime
315
});
316
});
317
318
QUnit.on("runEnd", (details) => {
319
this.results.summary = {
320
status: details.status,
321
testCounts: details.testCounts,
322
runtime: details.runtime
323
};
324
325
this.output();
326
});
327
}
328
329
output() {
330
console.log(JSON.stringify(this.results, null, 2));
331
}
332
}
333
334
// Initialize custom reporter
335
new JSONReporter();
336
```
337
338
### Event-based Test Monitoring
339
340
Monitor test progress and performance.
341
342
**Usage Examples:**
343
344
```javascript
345
// Performance monitoring
346
const performanceMonitor = {
347
slowTests: [],
348
threshold: 1000, // 1 second
349
350
init() {
351
QUnit.on("testEnd", (details) => {
352
if (details.runtime > this.threshold) {
353
this.slowTests.push({
354
name: details.name,
355
module: details.module,
356
runtime: details.runtime
357
});
358
}
359
});
360
361
QUnit.on("runEnd", () => {
362
if (this.slowTests.length > 0) {
363
console.warn("Slow tests detected:");
364
this.slowTests.forEach(test => {
365
console.warn(` ${test.module} > ${test.name}: ${test.runtime}ms`);
366
});
367
}
368
});
369
}
370
};
371
372
performanceMonitor.init();
373
```
374
375
## Supported Events
376
377
QUnit supports the following events (defined in src/events.js):
378
379
```javascript { .api }
380
/**
381
* Available event names:
382
* - 'error' - Uncaught errors (memory event)
383
* - 'runStart' - Test run begins
384
* - 'suiteStart' - Module execution begins
385
* - 'testStart' - Individual test begins
386
* - 'assertion' - Each assertion result
387
* - 'testEnd' - Individual test completes
388
* - 'suiteEnd' - Module execution completes
389
* - 'runEnd' - Test run completes (memory event)
390
*/
391
392
/**
393
* Memory events are replayed for late-registered listeners
394
* Events: 'error', 'runEnd'
395
*/
396
```
397
398
## Legacy Callback API
399
400
QUnit also supports legacy callbacks for backwards compatibility:
401
402
```javascript { .api }
403
/**
404
* Legacy callback functions (still supported but events preferred)
405
*/
406
QUnit.begin(callback) // Called before tests start
407
QUnit.testStart(callback) // Called when test starts
408
QUnit.log(callback) // Called for each assertion
409
QUnit.testDone(callback) // Called when test completes
410
QUnit.moduleStart(callback)// Called when module starts
411
QUnit.moduleDone(callback) // Called when module completes
412
QUnit.done(callback) // Called when all tests complete
413
```