Alexus
Alexus

Reputation: 1973

combine coverage reports using istanbul-combine

Let's say I have these coverage reports:

now I would like to combine these reports and generate a html report.

I'm using this istanbul-combine to do this kind of work. But it seems as if it couldn't find all these coverage json files and I wonder as why is that.

istanbul-combine -d coverage/reports -r lcov -r html /coverage/libs/test/**/coverage-final.json

At the end of the report generation process, it provides me an empty html report.

Upvotes: 3

Views: 5735

Answers (3)

Hayden McParlane
Hayden McParlane

Reputation: 79

I encountered this type of issue when combining multiple package coverage results in a monorepo. I used @skyboyer and @Alexus answer which worked really well and was nice and clean but the dependabot on GitHub came up with an indirect security vulnerability resulting from istanbul use. Using istanbuljs's nyc replacement for the istanbul CLI I implemented the same functionality. Unfortunately, it's not nearly as clean but here it is...

I had to rename all of the coverage-final.json files to something unique. Noting my output directory is coverage and the reporter used was json…

lerna exec -- 'export WORKING_DIR=$(basename $LERNA_PACKAGE_NAME) && cp ./<output dir>/coverage-final.json ./<output dir>/coverage-final-$(echo $WORKING_DIR).json'

After which I needed to place all of those files into a centralized directory…

mkdir -p ./coverage && lerna exec -- 'export WORKING_DIR=$(basename $LERNA_PACKAGE_NAME) && cp ./<output dir>/coverage-final-$(echo $WORKING_DIR).json ../../coverage/coverage-final-$(echo $WORKING_DIR).json'

This copied the package contents into a root-level directory named coverage. Moving forward, I needed to merge all of the copied results into one json file. For the output directory I used the same coverage directory at the root level…

nyc merge ./coverage ./coverage/coverage-final.json

And, finally, I needed to transform the result to lcov for input into coveralls (my use-case);

nyc report --reporter=lcov --temp-dir=coverage

Hope that helps! :-) Repository containing implementation

Upvotes: 1

Zdravko Kolev
Zdravko Kolev

Reputation: 1587

istanbul-combine will be deprecated in favor of istanbul report. I did a migration lately.

This was the old configuration that I was using with istanbul-combine:

istanbul-combine -d coverage -p none -r lcov -r cobertura coverage/hierarchical-grid/coverage-final.json coverage/tree-grid/coverage-final.json coverage/non-grid/coverage-final.json coverage/grid/coverage-final.json

Changed to:

istanbul report --dir coverage --include coverage/**/coverage-final.json lcov

Related Pull Request.

Upvotes: 5

Alexus
Alexus

Reputation: 1973

So I have found a different way to solve this problem. I wrote a small script, which does the following.

  • reads library directory and finds all coverage reports
  • reads coverage reports and corrects some incorrect data produced by jest
  • merges all reports data into one report
  • prints out the final report

mergeCoverage.js

const fs = require( 'fs-extra');
const glob = require('glob');
const { createReporter } = require('istanbul-api');
const istanbulCoverage = require('istanbul-lib-coverage');

const reporter = createReporter();

/* [ Configuration ] */
const rootDir = './coverage/libs';
const reportOut = './coverage/report';

const normalizeJestCoverage = ( obj ) => {
  const result = { ...obj };

  Object
  .entries( result )
  .filter( ([k, v] ) => v.data )
  .forEach( ([k, v] ) => {
    result[k] = v.data;
  });

  return result;
};

const mergeAllReports = ( coverageMap, reports ) => {
  if ( Array.isArray( reports ) === false ) {
    return;
  }

  reports.forEach( reportFile => {
    const coverageReport = fs.readJSONSync( reportFile );
    coverageMap.merge( normalizeJestCoverage( coverageReport ) );
  })
};

const findAllCoverageReports = ( path, callback ) => {
  glob( path, {}, ( err, reports )=>{
    callback( reports, err );
  });
};

const generateReport = ( coverageMap, types ) => {
  reporter.dir = reportOut;
  reporter.addAll(types || ['html', 'text'] );
  reporter.write( coverageMap );
};

async function main () {
  const coverageMap = istanbulCoverage.createCoverageMap( {} );

  findAllCoverageReports( rootDir + '/**/coverage-final.json', ( reports, err ) => {
    if ( Array.isArray( reports ) ) {
      mergeAllReports( coverageMap, reports );
      generateReport( coverageMap, [ 'text' ]  )
    }
  });
}

main().catch(err => {
  console.error(err);
  process.exit(1);
});

Upvotes: 3

Related Questions