Code coverage for Solidity testing
—
The primary interface for solidity-coverage, providing seamless integration with Hardhat's compilation and testing pipeline. The plugin registers a coverage task that instruments contracts, runs tests, and generates comprehensive coverage reports.
Automatically registers with Hardhat when required in configuration.
// In hardhat.config.js
require('solidity-coverage');
// Or in hardhat.config.ts
import 'solidity-coverage';The main coverage analysis task with extensive configuration options.
/**
* Generates a code coverage report for tests
* Instruments Solidity contracts, runs tests, and generates Istanbul reports
*/
npx hardhat coverage [options]
// Task options:
--testfiles <path> // Glob path to subset of test files to run
--solcoverjs <path> // Relative path to .solcover.js configuration file
--temp <path> // Relative path to temporary directory for artifacts
--sources <path> // Relative path to contracts directory
--matrix // Generate test matrix data instead of coverage reports
--abi // Generate human readable ABI list for analysisUsage Examples:
# Basic coverage run
npx hardhat coverage
# Run coverage on specific test files
npx hardhat coverage --testfiles "test/unit/**/*.js"
# Use custom configuration file
npx hardhat coverage --solcoverjs .solcover.custom.js
# Generate test matrix instead of coverage
npx hardhat coverage --matrix
# Generate ABI analysis
npx hardhat coverage --abiThe plugin automatically configures the Hardhat network for coverage analysis.
/**
* Network configuration applied during coverage runs
* These settings are automatically applied when SOLIDITY_COVERAGE env var is set
*/
interface HardhatNetworkConfig {
allowUnlimitedContractSize: boolean; // Allow large instrumented contracts
blockGasLimit: number; // Set to 0x1fffffffffffff for coverage
gas: number; // Set to 0xffffffffff for transactions
gasPrice: number; // Set to 0x01 for predictable costs
}The plugin hooks into Hardhat's compilation process to instrument contracts.
/**
* Compilation subtasks modified by the plugin:
* - TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT: Injects instrumented source code
* - TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE: Configures compiler settings
* - TASK_COMPILE_SOLIDITY_LOG_COMPILATION_ERRORS: Suppresses instrumentation warnings
*/
// Compiler settings automatically applied for coverage:
interface SolidityCompilerSettings {
metadata: {
useLiteralContent: false; // Reduce metadata size for instrumented contracts
};
optimizer: {
enabled: boolean; // Disabled unless viaIR is true
details?: OptimizerDetails; // Custom optimizer configuration
};
}Configuration through environment variables.
# Environment variables that affect plugin behavior:
SOLIDITY_COVERAGE=true # Activates coverage mode and network configuration
VIA_IR=true # Enables Solidity viaIR compilation modeUsage Examples:
# Run tests with coverage enabled
SOLIDITY_COVERAGE=true npx hardhat test
# Enable viaIR compilation mode for coverage
VIA_IR=true npx hardhat coverageLoads configuration from .solcover.js file in project root.
/**
* .solcover.js configuration file structure
* All options are optional and have sensible defaults
*/
module.exports = {
skipFiles: string[]; // Files/folders to exclude from instrumentation
istanbulReporter: string[]; // Report formats: html, lcov, text, json
istanbulFolder: string; // Custom output directory for reports
measureStatementCoverage: boolean; // Enable statement coverage measurement
measureFunctionCoverage: boolean; // Enable function coverage measurement
measureModifierCoverage: boolean; // Enable modifier coverage measurement
measureLineCoverage: boolean; // Enable line coverage measurement
measureBranchCoverage: boolean; // Enable branch coverage measurement
modifierWhitelist: string[]; // Specific modifiers to measure
configureYulOptimizer: boolean; // Configure Yul optimizer for coverage
viaIR: boolean; // Enable Solidity viaIR compilation
irMinimum: boolean; // Use minimal IR optimization settings
solcOptimizerDetails: object; // Custom Solidity optimizer configuration
// Workflow hooks for custom integration
onServerReady: (config) => void; // Called when coverage server is ready
onCompileComplete: (config) => void; // Called after contract compilation
onTestsComplete: (config) => void; // Called after all tests complete
onIstanbulComplete: (config) => void; // Called after coverage reports generated
onPreCompile: (config) => void; // Called before contract compilation
// Mocha test runner configuration
mocha: {
timeout: number; // Test timeout in milliseconds
reporter: string; // Mocha reporter to use
// ... other Mocha options
};
};Configuration Examples:
// Basic configuration
module.exports = {
skipFiles: ['contracts/mocks/', 'contracts/test/'],
istanbulReporter: ['html', 'lcov'],
};
// Advanced configuration with hooks
module.exports = {
skipFiles: ['contracts/mocks/'],
istanbulReporter: ['html', 'lcov', 'text', 'json'],
measureStatementCoverage: true,
measureFunctionCoverage: true,
measureModifierCoverage: true,
viaIR: true,
configureYulOptimizer: true,
onServerReady: () => {
console.log('Coverage analysis server started');
},
onTestsComplete: (config) => {
console.log('Tests completed, generating reports...');
},
mocha: {
timeout: 100000,
reporter: 'spec',
},
};Automatically generates Istanbul coverage reports in multiple formats.
/**
* Default report formats and locations:
* - HTML report: ./coverage/index.html (interactive web interface)
* - LCOV report: ./coverage/lcov.info (for CI/CD integration)
* - Text report: console output (terminal summary)
* - JSON report: ./coverage/coverage-final.json (machine readable)
* - Coverage summary: ./coverage.json (simplified format)
*/
// Output files created by coverage run:
interface CoverageOutputs {
'coverage/': {
'index.html': 'Interactive HTML coverage report';
'lcov.info': 'LCOV format for CI/CD tools';
'coverage-final.json': 'Detailed JSON coverage data';
};
'coverage.json': 'Simplified coverage summary';
'testMatrix.json'?: 'Test-to-code mapping (if --matrix flag used)';
'humanReadableAbis.json'?: 'ABI analysis (if --abi flag used)';
'mochaOutput.json'?: 'Mocha test results in JSON format';
}The plugin provides detailed error messages for common issues.
/**
* Common error scenarios and handling:
* - HardhatPluginError: Thrown for configuration and execution errors
* - Compilation errors: Invalid Solidity syntax preventing instrumentation
* - Network errors: Issues connecting to or configuring Hardhat network
* - File system errors: Missing contracts or insufficient permissions
* - Test failures: Coverage run fails if tests fail (unless configured otherwise)
*/
// Error message types:
interface PluginErrors {
'network-fail': 'Error when --network flag is used (not supported)';
'hardhat-viem': 'Compatibility warning for hardhat-viem plugin';
'tests-fail': 'Error when tests fail during coverage run';
'solcoverjs-fail': 'Error loading .solcover.js configuration';
'mocha-parallel-fail': 'Error when Mocha parallel mode is enabled';
}Works seamlessly with popular Ethereum testing frameworks.
/**
* Supported testing frameworks and libraries:
* - Hardhat (native integration)
* - Ethers.js (full compatibility)
* - Waffle (full compatibility)
* - Web3.js (full compatibility)
* - Truffle contract abstractions (compatibility layer)
* - Mocha (test runner integration)
* - Chai (assertion library support)
*/
// Test configuration considerations:
interface TestingConfig {
timeout: number; // Increase timeout for instrumented contracts
gas: number; // Use unlimited gas for coverage runs
gasPrice: number; // Use minimal gas price for predictable costs
allowUnlimitedContractSize: boolean; // Allow large instrumented contracts
}Testing Examples:
// Hardhat + Ethers.js
const { ethers } = require("hardhat");
describe("MyContract", function() {
it("should work with coverage", async function() {
const MyContract = await ethers.getContractFactory("MyContract");
const contract = await MyContract.deploy();
await contract.deployed();
const result = await contract.myFunction();
expect(result).to.equal(42);
});
});
// Hardhat + Waffle
const { waffle } = require("hardhat");
describe("MyContract", function() {
it("should work with coverage", async function() {
const [wallet] = waffle.provider.getWallets();
const contract = await waffle.deployContract(wallet, MyContract);
await expect(contract.myFunction()).to.emit(contract, 'MyEvent');
});
});Install with Tessl CLI
npx tessl i tessl/npm-solidity-coverage