Solidity-coverage tracks which lines are hit as your tests run by instrumenting the contracts with special solidity statements and detecting their execution in a coverage-enabled EVM.
As such, the API spans the full set of tasks typically required to run a solidity test suite. The table below shows how its core methods relate to the stages of a test run:
Additional Resources:
-
the library includes file system utilities for managing the disposable set of contracts/artifacts which coverage must use in lieu of the 'real' (uninstrumented) contracts.
-
a complete coverage tool/plugin implementation for Hardhat which can be used as a source if you're building something similar.
-
a coverage integration for the vitest framework which uses the API written by @wighawag
Example
const CoverageAPI = require("solidity-coverage/api");
const api = new CoverageAPI(options);Creates a coverage API instance. Configurable.
Parameters
optionsObject : API options
| Option |
Type |
Default |
Description |
|---|---|---|---|
| silent | Boolean | false | Suppress logging output |
| skipFiles | Array | [] |
Array of contracts or folders (with paths expressed relative to the contracts directory) that should be skipped when doing instrumentation. |
| istanbulFolder | String | ./coverage |
Folder location for Istanbul coverage reports. |
| istanbulReporter | Array | ['html', 'lcov', 'text', 'json'] |
Istanbul coverage reporters |
Instruments a set of sources to prepare them for compilation.
Parameters
contractsObject[]: Array of solidity sources and their paths
Returns Object[] in the same format as the contracts param, but with sources instrumented.
Example
const contracts = [{
source: "contract Simple { uint x = 5; }",
canonicalPath: "/Users/user/project/contracts/Simple.sol",
relativePath: "Simple.sol" // Optional, used for pretty printing.
},...]
const instrumented = api.instrument(contracts)Enables coverage data collection on a HardhatEVM provider. (You will need to create a hardhat provider with the correct VM settings as shown below before invoking this method.)
Parameters
providerObject: Hardhat provider
Returns Promise
Example
const { createProvider } = require("hardhat/internal/core/providers/construction");
const { resolveConfig } = require("hardhat/internal/core/config/config-resolution");
const { HARDHAT_NETWORK_NAME } = require("hardhat/plugins")
const api = new CoverageAPI( { ... } );
// Execute instrument and compiilation steps and then...
const config = resolveConfig("./", {});
config.networks[HARDHAT_NETWORK_NAME].allowUnlimitedContractSize = true;
config.networks[HARDHAT_NETWORK_NAME].blockGasLimit = api.gasLimitNumber;
config.networks[HARDHAT_NETWORK_NAME].gas = api.gasLimit;
config.networks[HARDHAT_NETWORK_NAME].gasPrice = api.gasPrice;
config.networks[HARDHAT_NETWORK_NAME].initialBaseFeePerGas = 0;
const provider = await createProvider(
config,
HARDHAT_NETWORK_NAME
)
await api.attachToHardhatVM(provider);Generates coverage report using IstanbulJS
Parameters
istanbulFolderString: (Optional) path to folder Istanbul will deposit coverage reports in.
Returns Promise
Example
await api.report('./coverage_4A3cd2b'); // Default folder name is 'coverage'Returns a copy of the hit map created during instrumentation. Useful if you'd like to delegate coverage collection to multiple processes.
Returns Object instrumentation data;
Example
const instrumented = api.instrument(contracts);
const data = api.getInstrumentationData();
save(data); // Pseudo-codeSets the hit map object generated during instrumentation. Useful if you'd like to collect or convert data to coverage for an instrumentation which was generated in a different process.
Example
const data = load(data); // Pseudo-code
api.setIntrumentationData(data);
// Client will collect data for the loaded map
await api.attachToHardhatVM(provider);
// Or to `report` instrumentation data which was collected in a different process.
const data = load(data); // Pseudo-code
api.setInstrumentationData(data);
api.report();const utils = require('solidity-coverage/utils');Many of the utils methods take a config object param which
defines the absolute paths to your project root and contracts directory.
Example
const config = {
workingDir: process.cwd(),
contractsDir: path.join(process.cwd(), 'contracts'),
}Loads .solcoverjs. Users may specify options in a .solcover.js config file which your
application needs to consume.
Parameters
configObject: See config above
Returns Object Normalized coverage config
Example
const solcoverJS = utils.loadSolcoverJS(config);
const api = new CoverageAPI(solcoverJS);Loads contracts from the filesystem in a format that can be passed directly to the
api.instrument method. Filters by an optional skipFiles parameter.
Parameters
configObject: See config aboveskipFilesString[]: (Optional) Array of files or folders to skip See API constructor
Returns Object with targets and skipped keys. These are Object arrays of contract sources
and paths.
Example
const {
targets,
skipped
} = utils.assembleFiles(config, ['Migrations.sol'])
const instrumented = api.instrument(targets);Returns a pair of canonically named temporary directory paths for contracts and artifacts. Instrumented assets can be compiled from and written to these so the unit tests can use them as sources.
Parameters
configObject: See config above
Returns Object with two absolute paths to disposable folders, tempContractsDir, tempArtifactsDir.
These directories are named .coverage_contracts and .coverage_artifacts.
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir)
// Later, you can call `utils.finish` to delete these...
utils.finish(config, api)Creates temporary directories to store instrumented contracts and their compilation artifacts in.
Parameters
configObject: See config abovetempContractsDirString: absolute path to temporary contracts directorytempArtifactsDirString: absolute path to temporary artifacts directory
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);Writes an array of instrumented sources in the object format returned by api.instrument to a temporary directory.
Parameters
contractsObject[]: array of contracts & paths generated by api.instrumentoriginalDirString: absolute path to original contracts directorytempDirString: absolute path to temp contracts directory (the destination of the save)
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);
const instrumented = api.instrument(contracts);
utils.save(instrumented, config.contractsDir, tempContractsDir);Deletes temporary folders. Is tolerant - if folders don't exist it will return silently.
Parameters
configObject: See config aboveapiObject: (Optional) coverage api instance whose ownfinishmethod will be called
Returns Promise
Example
await utils.finish(config, api);