Comprehensive JavaScript code coverage tool that computes statement, line, function and branch coverage with module loader hooks for transparent instrumentation
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
Collects and merges coverage objects from multiple test runs or sources.
/**
* Creates a collector for merging coverage data
* @param {CollectorOptions} options - Configuration options for the collector
*/
class Collector {
constructor(options?: CollectorOptions);
/**
* Adds a coverage object to the collector
* @param {Object} coverage - Coverage object (typically from global.__coverage__)
* @param {string} testName - Optional test name for identification
*/
add(coverage: Object, testName?: string): void;
/**
* Returns array of file paths that have coverage information
* @returns {string[]} Array of file paths
*/
files(): string[];
/**
* Returns coverage information for a specific file
* @param {string} fileName - The file path to get coverage for
* @returns {Object} File coverage object
*/
fileCoverageFor(fileName: string): Object;
/**
* Returns merged coverage information for all files
* @returns {Object} Complete merged coverage object
*/
getFinalCoverage(): Object;
/**
* Disposes the collector and reclaims temporary resources
*/
dispose(): void;
}
interface CollectorOptions {
/** Store implementation for temporary calculations (optional) */
store?: Store;
}Usage Examples:
const { Collector } = require('istanbul');
// Basic collection from global coverage
const collector = new Collector();
// Add coverage from instrumented code execution
global.__coverage__ = {}; // populated by instrumented code
collector.add(global.__coverage__);
// Add coverage from multiple test runs
collector.add(testRun1Coverage, 'unit-tests');
collector.add(testRun2Coverage, 'integration-tests');
// Access collected data
const files = collector.files();
console.log('Files with coverage:', files);
// Get coverage for specific file
const fileCoverage = collector.fileCoverageFor('src/app.js');
console.log('App.js coverage:', fileCoverage);
// Get final merged coverage
const finalCoverage = collector.getFinalCoverage();
// Clean up resources
collector.dispose();When multiple coverage objects are added to a collector, they are automatically merged:
const collector = new Collector();
// Coverage from first test run
const coverage1 = {
'app.js': {
s: { '1': 1, '2': 0, '3': 1 }, // statements
b: { '1': [1, 0] }, // branches
f: { '1': 1, '2': 0 } // functions
// ... other coverage data
}
};
// Coverage from second test run
const coverage2 = {
'app.js': {
s: { '1': 1, '2': 1, '3': 1 }, // statement 2 now covered
b: { '1': [1, 1] }, // both branches covered
f: { '1': 1, '2': 1 } // function 2 now covered
// ... other coverage data
}
};
collector.add(coverage1, 'test-run-1');
collector.add(coverage2, 'test-run-2');
// Final merged coverage combines both runs
const merged = collector.getFinalCoverage();
// Result: { 'app.js': { s: { '1': 2, '2': 1, '3': 2 }, b: { '1': [2, 1] }, f: { '1': 2, '2': 1 } } }Individual file coverage objects returned by fileCoverageFor() contain:
interface FileCoverage {
/** File path */
path: string;
/** Statement hit counts */
s: { [statementId: string]: number };
/** Branch hit counts (array for each branch condition) */
b: { [branchId: string]: number[] };
/** Function hit counts */
f: { [functionId: string]: number };
/** Function metadata and locations */
fnMap: { [functionId: string]: FunctionMapping };
/** Statement location metadata */
statementMap: { [statementId: string]: Location };
/** Branch location metadata and conditions */
branchMap: { [branchId: string]: BranchMapping };
/** Line hit counts (derived from statements) */
l: { [lineNumber: string]: number };
}
interface FunctionMapping {
name: string;
decl: Location;
loc: Location;
line: number;
}
interface BranchMapping {
loc: Location;
type: 'if' | 'switch' | 'cond-expr' | 'default-arg';
locations: Location[];
line: number;
}
interface Location {
start: { line: number; column: number };
end: { line: number; column: number };
}Collectors can use different store implementations for temporary calculations:
const { Collector, Store } = require('istanbul');
// Use memory store (default)
const collector1 = new Collector({
store: Store.create('memory')
});
// Use filesystem store for large datasets
const collector2 = new Collector({
store: Store.create('fslookup')
});
// Use temporary directory store
const collector3 = new Collector({
store: Store.create('tmp')
});Typical integration pattern with test runners:
const { Collector } = require('istanbul');
// Before tests
global.__coverage__ = {};
const collector = new Collector();
// After each test file/suite
if (global.__coverage__) {
collector.add(global.__coverage__);
global.__coverage__ = {}; // reset for next test
}
// After all tests
const finalCoverage = collector.getFinalCoverage();
// Generate reports using the collected coverage
const reporter = new Reporter();
reporter.addAll(['text', 'html', 'lcov']);
reporter.write(collector, true, () => {
console.log('Coverage reports generated');
collector.dispose();
});The collector validates coverage objects when they are added:
try {
collector.add(invalidCoverageObject);
} catch (error) {
console.error('Invalid coverage object:', error.message);
}Common issues include:
For long-running processes or large codebases:
// Create collector
const collector = new Collector();
// Process coverage data
collector.add(coverage1);
collector.add(coverage2);
// Get results
const finalCoverage = collector.getFinalCoverage();
// Important: dispose to free memory
collector.dispose();
// After dispose, collector should not be usedThe dispose() method is important for: