DEV Community

Cover image for Combine coverage reports from Electron tests
kontrollanten
kontrollanten

Posted on

Combine coverage reports from Electron tests

We're using electron-mocha to test main process and jest to test renderer process for the ProtonMail unofficial Desktop application. To keep track of the test coverage we'd like to create coverage reports and send to codecov, but that was more troublesome than I first thought.

There's a good thread in the electron-mocha GitHub repo that helped us along the way. But to collect all information in one place I'll describe how we solved it.

Coverage report with jest

Since jest has coverage support out of the box the only thing needed is yarn jest --coverage. Simple.

Coverage report with electron-mocha

This wasn't just as easy as jest. To begin with I added babel-plugin-istanbul to instrument the code, which make it possible to trace the coverage.

.babelrc.js

    "env": {
      "test_main": {
        "plugins": ["istanbul"]
      }
    },

I didn't get babel-plugin-istanbul to work with nyc so I took this solution from bennyn which just saves the coverage data into coverage/coverage-main.json:

src/main/tests/coverage-after.spec.js

import path from 'path';
import fs from 'fs-extra';

const writeCoverageReport = coverage => {
  const outputFile = path.resolve(process.cwd(), 'coverage/coverage-main.json');
  fs.outputJsonSync(outputFile, coverage);
};


after(() => {
  if (process.env.NODE_ENV === 'test_main') {
    console.info('--- Writing coverage report');
    writeCoverageReport((global).__coverage__);
  }
}); 

To create the coverage report we then run yarn cross-env NODE_ENV=test_main yarn electron-mocha --require @babel/register src/main/**/*.spec.js src/main/*.spec.js.

This solution has one problem. It'll only show coverage for files included by tests. If you don't have any test you'll get 100% coverage. Almighty bennyn had a solution for that also; require all JS files before creating the coverage report. In our case it ended up with this:

src/main/tests/coverage-after.spec.js

import glob from 'glob';
import path from 'path';
import fs from 'fs-extra';

const writeCoverageReport = coverage => {
  const outputFile = path.resolve(process.cwd(), 'coverage/coverage-main.json');
  fs.outputJsonSync(outputFile, coverage);
};

// Load all source files to get accurate coverage data
const loadSourceCode = () => {
  const intrumentedCode = path.join(__dirname, '..');

  glob(`${intrumentedCode}/**/*.js`, {
    sync: true,
  }).forEach(file => require(path.resolve(file)));
};

after(() => {
  if (process.env.NODE_ENV === 'test_main') {
    console.info('--- Load all files to collect coverage');
    loadSourceCode();
    console.info('--- Writing coverage report');
    writeCoverageReport((global).__coverage__);
  }
});

Tie the bag together

Now we have to separate scripts to create two separate coverage reports. Let tie it together to one combined report.

jest will create a coverage report in ./coverage and we configured our main test to also put the report in ./coverage. By installing nyc we can combine the reports inside ./coverage and output it to ./coverage.json. If your test files isn't excluded by nyc's default config, you need to add the following to your config in package.json:

  "nyc": {
    "exclude": [
      "src/main/**/*.spec.js"
    ]
  },

Now you can run yarn nyc merge coverage combine the reports. That's it. To print the report in terminal we can run yarn nyc report -t ./coverage, which creates a report from the coverage folder, and it should look like this:

You can see the whole implementation commit here and the follow up cleanup here.

Top comments (3)

Collapse
 
qm3ster profile image
Mihail Malo

Have you seen facebook-atom/jest-electron-runner? Perhaps you'll be able to escape the mocha.

Collapse
 
kontrollanten profile image
kontrollanten

Not until now. Thanks! That looks really interesting. Even though I don't like Facebook I like jest a lot. I'll negotiate with my moral to see if I can go 100% jest.

Collapse
 
qm3ster profile image
Mihail Malo

It's about as facebook as being 2% Jest, but with less painal :D