CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-istanbul

Comprehensive JavaScript code coverage tool that computes statement, line, function and branch coverage with module loader hooks for transparent instrumentation

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

collection.mddocs/

Coverage Collection

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.

Capabilities

Collector Class

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();

Coverage Merging

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 } } }

File Coverage Object Structure

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 };
}

Working with Stores

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')
});

Integration with Test Runners

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();
});

Coverage Data Validation

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:

  • Missing required fields: Coverage objects must have proper structure
  • Invalid file paths: File paths must be strings and should be absolute when possible
  • Malformed hit counts: Hit counts must be non-negative numbers
  • Inconsistent metadata: Statement/branch/function maps must align with hit count data

Memory Management

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 used

The dispose() method is important for:

  • Freeing temporary storage
  • Releasing file handles (for filesystem stores)
  • Cleaning up cached data
  • Preventing memory leaks in long-running processes

docs

cli.md

collection.md

configuration.md

hooks.md

index.md

instrumentation.md

reporting.md

storage.md

tree-summarizer.md

utilities.md

tile.json