Code coverage for Solidity testing
—
Helper functions for common coverage-related tasks including file discovery, configuration loading, temporary directory management, and Hardhat integration. These utilities are used internally by the plugin but can be useful for custom workflows.
Functions for discovering and organizing contract files for instrumentation.
/**
* Discovers and assembles contract files for instrumentation
* Handles both single files and directory structures
* @param config - Configuration object containing contracts directory
* @param skipFiles - Array of file patterns to exclude from instrumentation
* @returns Object containing targets to instrument and skipped files
*/
function assembleFiles(config: Config, skipFiles?: string[]): FileAssembly;
interface FileAssembly {
targets: FileTarget[]; // Files to be instrumented
skipped: FileTarget[]; // Files excluded from instrumentation
}
interface FileTarget {
canonicalPath: string; // Absolute path to file
relativePath: string; // Relative path from contracts directory
source: string; // File source code content
}
interface Config {
contractsDir: string; // Path to contracts directory
workingDir: string; // Project working directory
logger?: {
log: (message: string) => void;
};
}Usage Examples:
const utils = require('solidity-coverage/utils');
// Discover all contract files
const config = {
contractsDir: './contracts',
workingDir: process.cwd()
};
const { targets, skipped } = utils.assembleFiles(config, ['contracts/mocks/']);
console.log(`Found ${targets.length} contracts to instrument`);
console.log(`Skipped ${skipped.length} contracts`);Lower-level functions for organizing contract targets.
/**
* Filters contract targets and creates structured file objects
* Separates files to instrument from files to skip
* @param config - Configuration object
* @param targets - Array of contract file paths
* @param skipFiles - Array of file patterns to exclude
* @returns Object with filtered targets and skipped files
*/
function assembleTargets(config: Config, targets?: string[], skipFiles?: string[]): FileAssembly;
/**
* Processes skipFiles configuration including folder patterns
* Expands folder patterns to include all files within
* @param config - Configuration object
* @param targets - Array of all discovered contract files
* @param skipFiles - Array of file/folder patterns to skip
* @returns Array of absolute paths to skip
*/
function assembleSkipped(config: Config, targets: string[], skipFiles?: string[]): string[];Usage Examples:
// Manual target assembly
const contractPaths = [
'/project/contracts/Token.sol',
'/project/contracts/Crowdsale.sol',
'/project/contracts/test/TestToken.sol'
];
const skipPatterns = ['contracts/test/'];
const skippedPaths = utils.assembleSkipped(config, contractPaths, skipPatterns);
const { targets, skipped } = utils.assembleTargets(config, contractPaths, skippedPaths);Functions for loading and validating coverage configuration.
/**
* Loads and validates .solcover.js configuration file
* Merges with base configuration and applies sensible defaults
* @param config - Base configuration object (optional)
* @returns Merged coverage configuration object
*/
function loadSolcoverJS(config?: Config): CoverageConfig;
interface CoverageConfig {
// File and directory settings
skipFiles?: string[]; // Files/folders to exclude
cwd: string; // Working directory
originalContractsDir: string; // Original contracts directory
// Report settings
istanbulReporter?: string[]; // Report formats
istanbulFolder?: string; // Output directory
// Coverage measurement toggles
measureStatementCoverage?: boolean; // Statement coverage
measureFunctionCoverage?: boolean; // Function coverage
measureModifierCoverage?: boolean; // Modifier coverage
measureLineCoverage?: boolean; // Line coverage
measureBranchCoverage?: boolean; // Branch coverage
modifierWhitelist?: string[]; // Specific modifiers to measure
// Compilation settings
viaIR?: boolean; // viaIR compilation mode
usingSolcV4?: boolean; // Solidity v0.4.x compatibility
configureYulOptimizer?: boolean; // Yul optimizer configuration
solcOptimizerDetails?: object; // Custom optimizer settings
// Workflow hooks
onServerReady?: (config: Config) => void;
onCompileComplete?: (config: Config) => void;
onTestsComplete?: (config: Config) => void;
onIstanbulComplete?: (config: Config) => void;
onPreCompile?: (config: Config) => void;
// Test configuration
mocha?: object; // Mocha configuration
// Logging
log: (message: string) => void; // Logging function
}Usage Examples:
// Load default configuration
const config = utils.loadSolcoverJS();
// Load configuration with custom file
const customConfig = utils.loadSolcoverJS({
solcoverjs: '.solcover.custom.js',
workingDir: process.cwd()
});
// Example .solcover.js file:
module.exports = {
skipFiles: ['contracts/mocks/', 'contracts/test/'],
istanbulReporter: ['html', 'lcov', 'text'],
measureStatementCoverage: true,
measureFunctionCoverage: true,
onTestsComplete: () => console.log('Tests finished')
};Functions for reading source files and managing temporary directories.
/**
* Loads Solidity source code from file path
* @param filePath - Absolute path to source file
* @returns String containing source code
*/
function loadSource(filePath: string): string;
/**
* Sets up temporary directories for instrumented contracts and artifacts
* Creates directories and cleans up any existing temporary files
* @param config - Configuration object
* @param tempContractsDir - Path for temporary instrumented contracts
* @param tempArtifactsDir - Path for temporary compilation artifacts
*/
function setupTempFolders(config: Config, tempContractsDir: string, tempArtifactsDir: string): void;
/**
* Saves instrumented contract files to temporary directory
* Preserves directory structure from original contracts
* @param targets - Array of instrumented contract objects
* @param originalDir - Original contracts directory path
* @param tempDir - Temporary contracts directory path
*/
function save(targets: InstrumentedTarget[], originalDir: string, tempDir: string): void;Usage Examples:
const fs = require('fs');
const path = require('path');
// Load source file
const contractSource = utils.loadSource('/project/contracts/Token.sol');
// Setup temporary directories
const tempContractsDir = path.join(process.cwd(), '.coverage_contracts');
const tempArtifactsDir = path.join(process.cwd(), '.coverage_artifacts');
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);
// Save instrumented contracts
utils.save(instrumentedTargets, config.contractsDir, tempContractsDir);Functions for managing temporary directories and cleanup.
/**
* Generates canonical temporary directory paths
* Creates consistent naming for contracts and artifacts directories
* @param config - Configuration object
* @returns Object with temporary directory paths
*/
function getTempLocations(config: Config): TempLocations;
interface TempLocations {
tempContractsDir: string; // Path for temporary instrumented contracts
tempArtifactsDir: string; // Path for temporary compilation artifacts
}
/**
* Validates contract sources exist and cleans up temporary directories
* Removes any existing temporary files before starting
* @param config - Configuration object
* @param tempContractsDir - Temporary contracts directory
* @param tempArtifactsDir - Temporary artifacts directory
*/
function checkContext(config: Config, tempContractsDir: string, tempArtifactsDir: string): void;
/**
* Cleanup function removing temporary directories and calling API finish
* Should be called after coverage analysis completes
* @param config - Configuration object
* @param api - API instance (optional)
* @returns Promise that resolves when cleanup is complete
*/
function finish(config: Config, api?: API): Promise<void>;Usage Examples:
// Get temporary directory paths
const { tempContractsDir, tempArtifactsDir } = utils.getTempLocations(config);
// Validate and clean up before starting
utils.checkContext(config, tempContractsDir, tempArtifactsDir);
// ... run coverage analysis ...
// Clean up after completion
await utils.finish(config, api);Functions for working with file paths.
/**
* Converts absolute file path to relative path
* @param pathToFile - Absolute path to file
* @param pathToParent - Absolute path to parent directory
* @returns Relative path from parent to file
*/
function toRelativePath(pathToFile: string, pathToParent: string): string;Usage Examples:
const absolutePath = '/project/contracts/token/ERC20.sol';
const contractsDir = '/project/contracts';
const relativePath = utils.toRelativePath(absolutePath, contractsDir);
// Result: 'token/ERC20.sol'Functions for displaying coverage information.
/**
* Displays list of skipped contracts via console output
* Shows which files were excluded from coverage analysis
* @param config - Configuration object
* @param skipped - Array of skipped file objects (optional)
*/
function reportSkipped(config: Config, skipped?: FileTarget[]): void;Usage Examples:
// Report which files were skipped
const { targets, skipped } = utils.assembleFiles(config, ['contracts/mocks/']);
utils.reportSkipped(config, skipped);
// Console output:
// > Skipping instrumentation of:
// > contracts/mocks/MockToken.sol
// > contracts/mocks/MockCrowdsale.solFunctions for working with Hardhat providers and networks.
/**
* Gets account addresses from Hardhat network provider
* @param provider - Hardhat network provider instance
* @returns Promise resolving to array of account addresses
*/
function getAccountsHardhat(provider: HardhatProvider): Promise<string[]>;
/**
* Gets node version information from Hardhat provider
* @param provider - Hardhat network provider instance
* @returns Promise resolving to version string
*/
function getNodeInfoHardhat(provider: HardhatProvider): Promise<string>;
interface HardhatProvider {
send(method: string, params: any[]): Promise<any>;
}Internal utility functions used by the Hardhat plugin.
/**
* Parses test file paths from command line arguments
* @param files - File path string or glob pattern
* @returns Array of resolved test file paths
*/
function getTestFilePaths(files: string): string[];
/**
* Normalizes Hardhat configuration for coverage runs
* @param config - Hardhat configuration object
* @param args - Command line arguments (optional)
* @returns Normalized configuration
*/
function normalizeConfig(config: HardhatConfig, args?: object): HardhatConfig;
/**
* Checks if the Solidity configuration is using viaIR compilation
* @param solidity - Solidity configuration object
* @returns True if viaIR is enabled
*/
function isUsingViaIR(solidity: object): boolean;
/**
* Checks if the project is using Solidity v0.4.x
* @param solidity - Solidity configuration object
* @returns True if using Solidity v0.4.x
*/
function isUsingSolcV4(solidity: object): boolean;
/**
* Sets up Hardhat network configuration for coverage
* @param env - Hardhat environment
* @param api - API instance
* @param ui - UI instance
* @returns Promise resolving to provider
*/
function setupHardhatNetwork(env: any, api: API, ui: any): Promise<any>;Usage Examples:
const { ethers } = require('hardhat');
// Get available accounts
const accounts = await utils.getAccountsHardhat(ethers.provider);
console.log(`Found ${accounts.length} accounts`);
// Get node information
const nodeInfo = await utils.getNodeInfoHardhat(ethers.provider);
console.log(`Node version: ${nodeInfo}`);The utility functions provide error handling for common issues:
/**
* Common error scenarios handled by utilities:
* - Missing contracts directory
* - Invalid .solcover.js configuration syntax
* - File system permission errors
* - Invalid file paths or patterns
* - Temporary directory creation failures
*/
// Example error handling
try {
const config = utils.loadSolcoverJS();
} catch (error) {
if (error.message.includes('solcoverjs-fail')) {
console.error('Invalid .solcover.js configuration:', error.message);
}
}Complete Workflow Example:
const utils = require('solidity-coverage/utils');
const API = require('solidity-coverage/api');
async function runCustomCoverage() {
try {
// Load configuration
const config = utils.loadSolcoverJS();
// Initialize API
const api = new API(config);
// Discover contract files
const { targets, skipped } = utils.assembleFiles(config);
utils.reportSkipped(config, skipped);
// Setup temporary directories
const { tempContractsDir, tempArtifactsDir } = utils.getTempLocations(config);
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);
// Instrument contracts
const instrumented = api.instrument(targets);
utils.save(instrumented, config.contractsDir, tempContractsDir);
// ... compile and run tests ...
// Generate reports
await api.report();
// Clean up
await utils.finish(config, api);
} catch (error) {
console.error('Coverage failed:', error.message);
process.exit(1);
}
}Install with Tessl CLI
npx tessl i tessl/npm-solidity-coverage