0
# Coverage Collection
1
2
Coverage collection merges and processes coverage data from multiple sources and test runs. The Collector class aggregates coverage information and prepares it for report generation.
3
4
## Capabilities
5
6
### Collector Class
7
8
Collects and merges coverage objects from multiple test runs or sources.
9
10
```javascript { .api }
11
/**
12
* Creates a collector for merging coverage data
13
* @param {CollectorOptions} options - Configuration options for the collector
14
*/
15
class Collector {
16
constructor(options?: CollectorOptions);
17
18
/**
19
* Adds a coverage object to the collector
20
* @param {Object} coverage - Coverage object (typically from global.__coverage__)
21
* @param {string} testName - Optional test name for identification
22
*/
23
add(coverage: Object, testName?: string): void;
24
25
/**
26
* Returns array of file paths that have coverage information
27
* @returns {string[]} Array of file paths
28
*/
29
files(): string[];
30
31
/**
32
* Returns coverage information for a specific file
33
* @param {string} fileName - The file path to get coverage for
34
* @returns {Object} File coverage object
35
*/
36
fileCoverageFor(fileName: string): Object;
37
38
/**
39
* Returns merged coverage information for all files
40
* @returns {Object} Complete merged coverage object
41
*/
42
getFinalCoverage(): Object;
43
44
/**
45
* Disposes the collector and reclaims temporary resources
46
*/
47
dispose(): void;
48
}
49
50
interface CollectorOptions {
51
/** Store implementation for temporary calculations (optional) */
52
store?: Store;
53
}
54
```
55
56
**Usage Examples:**
57
58
```javascript
59
const { Collector } = require('istanbul');
60
61
// Basic collection from global coverage
62
const collector = new Collector();
63
64
// Add coverage from instrumented code execution
65
global.__coverage__ = {}; // populated by instrumented code
66
collector.add(global.__coverage__);
67
68
// Add coverage from multiple test runs
69
collector.add(testRun1Coverage, 'unit-tests');
70
collector.add(testRun2Coverage, 'integration-tests');
71
72
// Access collected data
73
const files = collector.files();
74
console.log('Files with coverage:', files);
75
76
// Get coverage for specific file
77
const fileCoverage = collector.fileCoverageFor('src/app.js');
78
console.log('App.js coverage:', fileCoverage);
79
80
// Get final merged coverage
81
const finalCoverage = collector.getFinalCoverage();
82
83
// Clean up resources
84
collector.dispose();
85
```
86
87
### Coverage Merging
88
89
When multiple coverage objects are added to a collector, they are automatically merged:
90
91
```javascript
92
const collector = new Collector();
93
94
// Coverage from first test run
95
const coverage1 = {
96
'app.js': {
97
s: { '1': 1, '2': 0, '3': 1 }, // statements
98
b: { '1': [1, 0] }, // branches
99
f: { '1': 1, '2': 0 } // functions
100
// ... other coverage data
101
}
102
};
103
104
// Coverage from second test run
105
const coverage2 = {
106
'app.js': {
107
s: { '1': 1, '2': 1, '3': 1 }, // statement 2 now covered
108
b: { '1': [1, 1] }, // both branches covered
109
f: { '1': 1, '2': 1 } // function 2 now covered
110
// ... other coverage data
111
}
112
};
113
114
collector.add(coverage1, 'test-run-1');
115
collector.add(coverage2, 'test-run-2');
116
117
// Final merged coverage combines both runs
118
const merged = collector.getFinalCoverage();
119
// Result: { 'app.js': { s: { '1': 2, '2': 1, '3': 2 }, b: { '1': [2, 1] }, f: { '1': 2, '2': 1 } } }
120
```
121
122
### File Coverage Object Structure
123
124
Individual file coverage objects returned by `fileCoverageFor()` contain:
125
126
```javascript { .api }
127
interface FileCoverage {
128
/** File path */
129
path: string;
130
131
/** Statement hit counts */
132
s: { [statementId: string]: number };
133
134
/** Branch hit counts (array for each branch condition) */
135
b: { [branchId: string]: number[] };
136
137
/** Function hit counts */
138
f: { [functionId: string]: number };
139
140
/** Function metadata and locations */
141
fnMap: { [functionId: string]: FunctionMapping };
142
143
/** Statement location metadata */
144
statementMap: { [statementId: string]: Location };
145
146
/** Branch location metadata and conditions */
147
branchMap: { [branchId: string]: BranchMapping };
148
149
/** Line hit counts (derived from statements) */
150
l: { [lineNumber: string]: number };
151
}
152
153
interface FunctionMapping {
154
name: string;
155
decl: Location;
156
loc: Location;
157
line: number;
158
}
159
160
interface BranchMapping {
161
loc: Location;
162
type: 'if' | 'switch' | 'cond-expr' | 'default-arg';
163
locations: Location[];
164
line: number;
165
}
166
167
interface Location {
168
start: { line: number; column: number };
169
end: { line: number; column: number };
170
}
171
```
172
173
### Working with Stores
174
175
Collectors can use different store implementations for temporary calculations:
176
177
```javascript
178
const { Collector, Store } = require('istanbul');
179
180
// Use memory store (default)
181
const collector1 = new Collector({
182
store: Store.create('memory')
183
});
184
185
// Use filesystem store for large datasets
186
const collector2 = new Collector({
187
store: Store.create('fslookup')
188
});
189
190
// Use temporary directory store
191
const collector3 = new Collector({
192
store: Store.create('tmp')
193
});
194
```
195
196
### Integration with Test Runners
197
198
Typical integration pattern with test runners:
199
200
```javascript
201
const { Collector } = require('istanbul');
202
203
// Before tests
204
global.__coverage__ = {};
205
const collector = new Collector();
206
207
// After each test file/suite
208
if (global.__coverage__) {
209
collector.add(global.__coverage__);
210
global.__coverage__ = {}; // reset for next test
211
}
212
213
// After all tests
214
const finalCoverage = collector.getFinalCoverage();
215
216
// Generate reports using the collected coverage
217
const reporter = new Reporter();
218
reporter.addAll(['text', 'html', 'lcov']);
219
reporter.write(collector, true, () => {
220
console.log('Coverage reports generated');
221
collector.dispose();
222
});
223
```
224
225
### Coverage Data Validation
226
227
The collector validates coverage objects when they are added:
228
229
```javascript
230
try {
231
collector.add(invalidCoverageObject);
232
} catch (error) {
233
console.error('Invalid coverage object:', error.message);
234
}
235
```
236
237
Common issues include:
238
- **Missing required fields**: Coverage objects must have proper structure
239
- **Invalid file paths**: File paths must be strings and should be absolute when possible
240
- **Malformed hit counts**: Hit counts must be non-negative numbers
241
- **Inconsistent metadata**: Statement/branch/function maps must align with hit count data
242
243
### Memory Management
244
245
For long-running processes or large codebases:
246
247
```javascript
248
// Create collector
249
const collector = new Collector();
250
251
// Process coverage data
252
collector.add(coverage1);
253
collector.add(coverage2);
254
255
// Get results
256
const finalCoverage = collector.getFinalCoverage();
257
258
// Important: dispose to free memory
259
collector.dispose();
260
261
// After dispose, collector should not be used
262
```
263
264
The `dispose()` method is important for:
265
- Freeing temporary storage
266
- Releasing file handles (for filesystem stores)
267
- Cleaning up cached data
268
- Preventing memory leaks in long-running processes