0
# Report Generation
1
2
Report generation creates coverage reports in various formats including HTML, LCOV, text, and JSON. Istanbul provides both high-level Reporter class for multiple formats and individual Report classes for specific formats.
3
4
## Capabilities
5
6
### Reporter Class
7
8
High-level reporter for generating multiple coverage report formats from collected coverage data.
9
10
```javascript { .api }
11
/**
12
* Creates a multi-format reporter
13
* @param {Configuration} cfg - Configuration object (optional, uses default if falsy)
14
* @param {string} dir - Directory to write reports (optional, uses config default if falsy)
15
*/
16
class Reporter {
17
constructor(cfg?: Configuration, dir?: string);
18
19
/**
20
* Adds a report format to be generated
21
* @param {string} fmt - Report format name (e.g., 'html', 'lcov', 'text')
22
*/
23
add(fmt: string): void;
24
25
/**
26
* Adds multiple report formats to be generated
27
* @param {string[]} fmts - Array of report format names
28
*/
29
addAll(fmts: string[]): void;
30
31
/**
32
* Writes all configured reports
33
* @param {Collector} collector - Collector containing coverage data
34
* @param {boolean} sync - Whether to write synchronously
35
* @param {Function} callback - Callback function called when all reports are written
36
*/
37
write(collector: Collector, sync: boolean, callback?: () => void): void;
38
}
39
```
40
41
**Usage Examples:**
42
43
```javascript
44
const { Reporter, Collector } = require('istanbul');
45
46
// Basic usage
47
const reporter = new Reporter();
48
reporter.addAll(['text', 'html', 'lcov']);
49
50
const collector = new Collector();
51
// ... add coverage data to collector
52
53
reporter.write(collector, true, () => {
54
console.log('All reports generated successfully!');
55
});
56
57
// With custom configuration and directory
58
const config = require('istanbul').config.loadFile('.istanbul.yml');
59
const reporter2 = new Reporter(config, './coverage-output');
60
reporter2.add('html');
61
reporter2.add('json-summary');
62
reporter2.write(collector, false, callback);
63
```
64
65
### Report Factory Class
66
67
Factory for creating individual report instances and accessing available report types.
68
69
```javascript { .api }
70
/**
71
* Factory class for creating individual reports
72
*/
73
class Report {
74
/**
75
* Creates a report of the specified type
76
* @param {string} type - Report type name
77
* @param {Object} opts - Report-specific options
78
* @returns {Report} Report instance
79
*/
80
static create(type: string, opts?: Object): Report;
81
82
/**
83
* Registers a new report implementation
84
* @param {Function} constructor - Report constructor function
85
*/
86
static register(constructor: Function): void;
87
88
/**
89
* Returns array of available report format names
90
* @returns {string[]} Available report types
91
*/
92
static getReportList(): string[];
93
94
/**
95
* Returns one-line summary of what this report does
96
* @returns {string} Report synopsis
97
*/
98
synopsis(): string;
99
100
/**
101
* Returns default configuration object for this report
102
* @returns {Object} Default configuration with overrideable keys
103
*/
104
getDefaultConfig(): Object;
105
106
/**
107
* Writes the report using coverage data from collector
108
* @param {Collector} collector - Collector with coverage data
109
* @param {boolean} sync - Whether to write synchronously
110
*/
111
writeReport(collector: Collector, sync?: boolean): void;
112
}
113
```
114
115
**Usage Examples:**
116
117
```javascript
118
// Get available report types
119
const availableReports = Report.getReportList();
120
console.log('Available reports:', availableReports);
121
// Output: ['text', 'text-summary', 'html', 'lcov', 'json', ...]
122
123
// Create individual reports
124
const htmlReport = Report.create('html', {
125
dir: './html-coverage'
126
});
127
128
const lcovReport = Report.create('lcov', {
129
file: 'coverage.lcov'
130
});
131
132
// Use individual reports
133
htmlReport.writeReport(collector, true);
134
lcovReport.writeReport(collector, true);
135
136
// Get report information
137
console.log('HTML report:', htmlReport.synopsis());
138
console.log('Default config:', htmlReport.getDefaultConfig());
139
```
140
141
### Built-in Report Types
142
143
Istanbul includes several built-in report formats:
144
145
#### Text Reports
146
147
```javascript { .api }
148
// Text-based console output with detailed coverage information
149
const textReport = Report.create('text', {
150
file: null // null = console output, string = file path
151
});
152
153
// Summary text report with just the totals
154
const summaryReport = Report.create('text-summary', {
155
file: null // null = console output
156
});
157
158
// LCOV format output to console
159
const textLcovReport = Report.create('text-lcov');
160
```
161
162
#### File-based Reports
163
164
```javascript { .api }
165
// HTML report with interactive browsing
166
const htmlReport = Report.create('html', {
167
dir: './coverage', // output directory
168
verbose: true, // include source code
169
linkMapper: null, // function to map file paths to URLs
170
subdir: '', // subdirectory within dir
171
watermarks: { // coverage watermarks for colors
172
statements: [50, 80],
173
functions: [50, 80],
174
branches: [50, 80],
175
lines: [50, 80]
176
}
177
});
178
179
// LCOV tracefile format
180
const lcovReport = Report.create('lcov', {
181
dir: './coverage',
182
file: 'lcov.info' // output filename
183
});
184
185
// LCOV format only (no HTML)
186
const lcovOnlyReport = Report.create('lcovonly', {
187
file: 'coverage.lcov'
188
});
189
190
// JSON coverage data
191
const jsonReport = Report.create('json', {
192
file: 'coverage.json'
193
});
194
195
// JSON summary metrics only
196
const jsonSummaryReport = Report.create('json-summary', {
197
file: 'coverage-summary.json'
198
});
199
```
200
201
#### XML Reports
202
203
```javascript { .api }
204
// Clover XML format (for Jenkins, etc.)
205
const cloverReport = Report.create('clover', {
206
dir: './coverage',
207
file: 'clover.xml'
208
});
209
210
// Cobertura XML format
211
const coberturaReport = Report.create('cobertura', {
212
dir: './coverage',
213
file: 'cobertura-coverage.xml'
214
});
215
```
216
217
#### CI/CD Integration Reports
218
219
```javascript { .api }
220
// TeamCity service messages
221
const teamcityReport = Report.create('teamcity', {
222
file: null, // output to console
223
blockName: null // TeamCity block name
224
});
225
226
// No-op report (for disabling output)
227
const noneReport = Report.create('none');
228
```
229
230
### Report Configuration Options
231
232
Each report type accepts specific configuration options:
233
234
```javascript { .api }
235
interface ReportOptions {
236
/** Output directory for file-based reports */
237
dir?: string;
238
239
/** Output filename (for single-file reports) */
240
file?: string;
241
242
/** Coverage watermarks for color coding */
243
watermarks?: {
244
statements: [number, number];
245
functions: [number, number];
246
branches: [number, number];
247
lines: [number, number];
248
};
249
250
/** Whether to include verbose information */
251
verbose?: boolean;
252
253
/** Custom subdirectory within main output directory */
254
subdir?: string;
255
256
/** Function to map file paths to URLs (for HTML reports) */
257
linkMapper?: (filePath: string) => string;
258
259
/** TeamCity block name (for teamcity reports) */
260
blockName?: string;
261
}
262
```
263
264
### Custom Report Types
265
266
You can register custom report implementations:
267
268
```javascript
269
class CustomReport {
270
constructor(opts) {
271
this.opts = opts || {};
272
}
273
274
synopsis() {
275
return 'Custom coverage report format';
276
}
277
278
getDefaultConfig() {
279
return { file: 'custom-coverage.txt' };
280
}
281
282
writeReport(collector, sync) {
283
const coverage = collector.getFinalCoverage();
284
// ... custom report generation logic
285
}
286
}
287
288
// Register the custom report
289
Report.register(CustomReport);
290
291
// Use it
292
const customReport = Report.create('CustomReport', {
293
outputPath: './custom-output'
294
});
295
```
296
297
### Watermarks and Thresholds
298
299
Coverage watermarks determine color coding in reports:
300
301
```javascript
302
const reporter = new Reporter(null, './coverage');
303
304
// Configure watermarks for HTML report
305
reporter.add('html');
306
const htmlReport = Report.create('html', {
307
watermarks: {
308
statements: [70, 90], // Red < 70%, Yellow 70-90%, Green > 90%
309
branches: [60, 80],
310
functions: [75, 95],
311
lines: [65, 85]
312
}
313
});
314
```
315
316
### Synchronous vs Asynchronous Writing
317
318
```javascript
319
// Synchronous writing (blocks until complete)
320
reporter.write(collector, true, () => {
321
console.log('Reports written synchronously');
322
});
323
324
// Asynchronous writing (non-blocking)
325
reporter.write(collector, false, () => {
326
console.log('Reports written asynchronously');
327
});
328
```
329
330
### Error Handling
331
332
```javascript
333
try {
334
const reporter = new Reporter();
335
reporter.add('html');
336
reporter.add('invalidformat'); // This will throw
337
} catch (error) {
338
console.error('Invalid report format:', error.message);
339
}
340
341
// Handle write errors
342
reporter.write(collector, true, (error) => {
343
if (error) {
344
console.error('Report generation failed:', error);
345
} else {
346
console.log('Reports generated successfully');
347
}
348
});
349
```
350
351
### Integration Patterns
352
353
Common patterns for report generation:
354
355
```javascript
356
const { Instrumenter, Collector, Reporter } = require('istanbul');
357
358
// Complete workflow
359
function generateCoverageReports() {
360
// 1. Collect coverage
361
const collector = new Collector();
362
collector.add(global.__coverage__);
363
364
// 2. Setup reporter
365
const reporter = new Reporter();
366
reporter.addAll(['text-summary', 'html', 'lcov']);
367
368
// 3. Generate reports
369
reporter.write(collector, true, () => {
370
console.log('Coverage reports generated in ./coverage/');
371
collector.dispose();
372
});
373
}
374
375
// With error handling
376
function generateReportsWithErrorHandling() {
377
try {
378
const collector = new Collector();
379
if (global.__coverage__ && Object.keys(global.__coverage__).length > 0) {
380
collector.add(global.__coverage__);
381
382
const reporter = new Reporter();
383
reporter.addAll(['text', 'html']);
384
385
reporter.write(collector, true, (error) => {
386
if (error) {
387
console.error('Failed to generate reports:', error);
388
} else {
389
console.log('Coverage reports generated successfully');
390
}
391
collector.dispose();
392
});
393
} else {
394
console.warn('No coverage data found');
395
}
396
} catch (error) {
397
console.error('Coverage reporting error:', error);
398
}
399
}
400
```