0
# Reporting System
1
2
Jasmine provides a built-in console reporter with support for custom reporters, parallel execution aggregation, and detailed failure reporting with color output and flexible formatting options.
3
4
## Capabilities
5
6
### ConsoleReporter Class
7
8
Default console output reporter providing formatted test results with color support and detailed failure information.
9
10
```javascript { .api }
11
/**
12
* A reporter that prints spec and suite results to the console
13
* A ConsoleReporter is installed by default
14
*/
15
class ConsoleReporter {
16
constructor();
17
18
/** Required capability declaration for parallel support */
19
reporterCapabilities: { parallel: true };
20
21
/** Default command to reproduce random seed results */
22
randomSeedReproductionCmd(seed: string): string;
23
}
24
```
25
26
### Reporter Configuration
27
28
Configure the console reporter with custom options and behavior.
29
30
```javascript { .api }
31
/**
32
* Configures the reporter with custom options
33
* @param options - Configuration options for the reporter
34
*/
35
setOptions(options: ConsoleReporterOptions): void;
36
37
interface ConsoleReporterOptions {
38
/** Whether to colorize the output */
39
showColors?: boolean;
40
/** Custom print function for output */
41
print?: (text: string) => void;
42
/** Function to filter/modify stack traces */
43
stackFilter?: (stack: string) => string;
44
/** Function that takes a random seed and returns the command to reproduce that seed */
45
randomSeedReproductionCmd?: (seed: string) => string;
46
/** Whether to list pending specs even if there are failures */
47
alwaysListPendingSpecs?: boolean;
48
}
49
```
50
51
**Usage Examples:**
52
53
```javascript
54
const { ConsoleReporter } = require('jasmine');
55
56
const reporter = new ConsoleReporter();
57
58
// Basic configuration
59
reporter.setOptions({
60
showColors: true,
61
alwaysListPendingSpecs: true
62
});
63
64
// Custom print function (e.g., for logging)
65
reporter.setOptions({
66
print: (text) => {
67
fs.appendFileSync('test-output.log', text);
68
process.stdout.write(text);
69
}
70
});
71
72
// Custom stack filter
73
reporter.setOptions({
74
stackFilter: (stack) => {
75
// Remove internal jasmine frames
76
return stack.split('\n')
77
.filter(line => !line.includes('node_modules/jasmine'))
78
.join('\n');
79
}
80
});
81
82
// Custom seed reproduction command
83
reporter.setOptions({
84
randomSeedReproductionCmd: (seed) => `npm test -- --seed=${seed}`
85
});
86
```
87
88
### Reporter Lifecycle Methods
89
90
Implement custom reporters by providing lifecycle callback methods.
91
92
```javascript { .api }
93
interface Reporter {
94
/** Called once at the beginning of the test suite */
95
jasmineStarted?(suiteInfo: JasmineStartedInfo): void;
96
97
/** Called once at the end of the test suite */
98
jasmineDone?(result: JasmineDoneInfo): void;
99
100
/** Called after each individual spec completes */
101
specDone?(result: SpecResult): void;
102
103
/** Called after each suite completes */
104
suiteDone?(result: SuiteResult): void;
105
106
/** Capability declaration for parallel support */
107
reporterCapabilities?: { parallel?: boolean };
108
}
109
110
interface JasmineStartedInfo {
111
/** Total number of specs defined (may be undefined in parallel mode) */
112
totalSpecsDefined?: number;
113
/** Randomization configuration */
114
order?: {
115
/** Whether specs are running in random order */
116
random: boolean;
117
/** Random seed being used */
118
seed: string;
119
};
120
/** Whether running in parallel mode */
121
parallel?: boolean;
122
/** Number of workers (only present in parallel mode) */
123
numWorkers?: number;
124
}
125
126
interface SpecResult {
127
/** Unique identifier for the spec */
128
id: string;
129
/** The spec's description */
130
description: string;
131
/** Full name including parent suite names */
132
fullName: string;
133
/** Array of failed expectations */
134
failedExpectations: FailedExpectation[];
135
/** Array of passed expectations */
136
passedExpectations: PassedExpectation[];
137
/** Reason for pending status if applicable */
138
pendingReason?: string;
139
/** Final status of the spec */
140
status: 'passed' | 'failed' | 'pending' | 'disabled';
141
/** Debug log entries if any */
142
debugLogs?: DebugLogEntry[];
143
/** Execution time in milliseconds */
144
duration?: number;
145
}
146
147
interface SuiteResult {
148
/** Unique identifier for the suite */
149
id: string;
150
/** The suite's description */
151
description: string;
152
/** Full name including parent suite names */
153
fullName: string;
154
/** Array of failed expectations from beforeAll/afterAll */
155
failedExpectations: FailedExpectation[];
156
/** Final status of the suite */
157
status: 'passed' | 'failed' | 'disabled';
158
}
159
```
160
161
### Custom Reporter Examples
162
163
Create custom reporters for various output formats and integrations.
164
165
**JSON Reporter:**
166
167
```javascript
168
class JSONReporter {
169
constructor() {
170
this.results = [];
171
this.startTime = null;
172
}
173
174
jasmineStarted(suiteInfo) {
175
this.startTime = Date.now();
176
console.log(JSON.stringify({
177
event: 'suiteStarted',
178
totalSpecs: suiteInfo.totalSpecsDefined,
179
random: suiteInfo.order?.random,
180
seed: suiteInfo.order?.seed
181
}));
182
}
183
184
specDone(result) {
185
this.results.push({
186
description: result.fullName,
187
status: result.status,
188
duration: result.duration,
189
failedExpectations: result.failedExpectations.map(fe => ({
190
message: fe.message,
191
stack: fe.stack
192
}))
193
});
194
}
195
196
jasmineDone(result) {
197
console.log(JSON.stringify({
198
event: 'suiteCompleted',
199
overallStatus: result.overallStatus,
200
totalTime: Date.now() - this.startTime,
201
specs: this.results
202
}));
203
}
204
}
205
206
// Usage
207
const jasmine = new Jasmine();
208
jasmine.addReporter(new JSONReporter());
209
```
210
211
**JUnit XML Reporter:**
212
213
```javascript
214
const fs = require('fs');
215
216
class JUnitReporter {
217
constructor(options = {}) {
218
this.outputFile = options.outputFile || 'test-results.xml';
219
this.results = [];
220
}
221
222
specDone(result) {
223
this.results.push(result);
224
}
225
226
jasmineDone(result) {
227
const xml = this.generateJUnitXML(this.results, result);
228
fs.writeFileSync(this.outputFile, xml);
229
}
230
231
generateJUnitXML(specs, suiteResult) {
232
const totalTests = specs.length;
233
const failures = specs.filter(s => s.status === 'failed').length;
234
const skipped = specs.filter(s => s.status === 'pending').length;
235
236
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
237
xml += `<testsuite tests="${totalTests}" failures="${failures}" skipped="${skipped}" time="${suiteResult.totalTime / 1000}">\n`;
238
239
specs.forEach(spec => {
240
xml += ` <testcase name="${this.escapeXml(spec.description)}" time="${spec.duration / 1000}">\n`;
241
242
if (spec.status === 'failed') {
243
spec.failedExpectations.forEach(failure => {
244
xml += ` <failure message="${this.escapeXml(failure.message)}">\n`;
245
xml += ` ${this.escapeXml(failure.stack)}\n`;
246
xml += ' </failure>\n';
247
});
248
} else if (spec.status === 'pending') {
249
xml += ` <skipped message="Pending: ${this.escapeXml(spec.pendingReason || 'No reason given')}"/>\n`;
250
}
251
252
xml += ' </testcase>\n';
253
});
254
255
xml += '</testsuite>\n';
256
return xml;
257
}
258
259
escapeXml(str) {
260
return (str || '').replace(/[<>&'"]/g, (char) => {
261
switch (char) {
262
case '<': return '<';
263
case '>': return '>';
264
case '&': return '&';
265
case '"': return '"';
266
case "'": return ''';
267
default: return char;
268
}
269
});
270
}
271
}
272
273
// Usage
274
const jasmine = new Jasmine();
275
jasmine.addReporter(new JUnitReporter({ outputFile: 'junit-results.xml' }));
276
```
277
278
### Parallel Reporter Support
279
280
Create reporters that work with parallel execution by implementing proper capabilities.
281
282
```javascript { .api }
283
interface ParallelReporter extends Reporter {
284
/** Required for parallel execution support */
285
reporterCapabilities: {
286
parallel: true;
287
};
288
}
289
```
290
291
**Parallel-Compatible Reporter:**
292
293
```javascript
294
class ParallelFileReporter {
295
constructor(options = {}) {
296
this.outputFile = options.outputFile || 'parallel-results.log';
297
this.reporterCapabilities = { parallel: true };
298
}
299
300
jasmineStarted(suiteInfo) {
301
const message = `Started parallel execution with ${suiteInfo.numWorkers || 'unknown'} workers\n`;
302
fs.appendFileSync(this.outputFile, message);
303
}
304
305
specDone(result) {
306
// This will be called from multiple worker processes
307
const message = `${new Date().toISOString()} - ${result.fullName}: ${result.status}\n`;
308
fs.appendFileSync(this.outputFile, message);
309
}
310
311
jasmineDone(result) {
312
const message = `Completed parallel execution: ${result.overallStatus} in ${result.totalTime}ms with ${result.numWorkers} workers\n`;
313
fs.appendFileSync(this.outputFile, message);
314
}
315
}
316
317
// Usage with ParallelRunner
318
const ParallelRunner = require('jasmine/parallel');
319
const runner = new ParallelRunner({ numWorkers: 4 });
320
runner.addReporter(new ParallelFileReporter({ outputFile: 'parallel-test.log' }));
321
```
322
323
### Default Reporter Configuration
324
325
Configure the built-in console reporter through the runner's configuration methods.
326
327
```javascript { .api }
328
/**
329
* Configures the default reporter that is installed if no other reporter is specified
330
* @param options - Configuration options for the default console reporter
331
*/
332
configureDefaultReporter(options: ConsoleReporterOptions): void;
333
```
334
335
**Usage Examples:**
336
337
```javascript
338
const Jasmine = require('jasmine');
339
const jasmine = new Jasmine();
340
341
// Configure default reporter
342
jasmine.configureDefaultReporter({
343
showColors: process.stdout.isTTY,
344
alwaysListPendingSpecs: false,
345
print: (text) => {
346
// Custom print function
347
process.stdout.write(text);
348
}
349
});
350
351
// For parallel runner
352
const ParallelRunner = require('jasmine/parallel');
353
const runner = new ParallelRunner();
354
355
runner.configureDefaultReporter({
356
showColors: true,
357
alwaysListPendingSpecs: true
358
});
359
```
360
361
### Multiple Reporter Support
362
363
Use multiple reporters simultaneously for different output formats.
364
365
```javascript
366
const Jasmine = require('jasmine');
367
const jasmine = new Jasmine();
368
369
// Clear default reporter
370
jasmine.clearReporters();
371
372
// Add multiple custom reporters
373
jasmine.addReporter(new JSONReporter());
374
jasmine.addReporter(new JUnitReporter({ outputFile: 'junit.xml' }));
375
jasmine.addReporter(new ConsoleReporter());
376
377
await jasmine.execute();
378
```
379
380
### Reporter Error Handling
381
382
Handle reporter errors and failures gracefully.
383
384
```javascript
385
class SafeReporter {
386
constructor(wrappedReporter) {
387
this.wrapped = wrappedReporter;
388
this.reporterCapabilities = wrappedReporter.reporterCapabilities;
389
}
390
391
jasmineStarted(suiteInfo) {
392
try {
393
this.wrapped.jasmineStarted?.(suiteInfo);
394
} catch (error) {
395
console.error('Reporter error in jasmineStarted:', error);
396
}
397
}
398
399
specDone(result) {
400
try {
401
this.wrapped.specDone?.(result);
402
} catch (error) {
403
console.error('Reporter error in specDone:', error);
404
}
405
}
406
407
jasmineDone(result) {
408
try {
409
this.wrapped.jasmineDone?.(result);
410
} catch (error) {
411
console.error('Reporter error in jasmineDone:', error);
412
}
413
}
414
}
415
416
// Usage
417
const jasmine = new Jasmine();
418
jasmine.addReporter(new SafeReporter(new CustomReporter()));
419
```