Combine coverage reports from Electron tests
Tags: electron, testing, javascript, devops
Published: 2019-03-10 09:35:42

We're using [electron-mocha](https://github.com/jprichardson/electron-mocha) to test main process and [jest](http://jestjs.io) to test renderer process for the [ProtonMail unofficial Desktop](https://github.com/protonmail-desktop/application) application. To keep track of the test coverage we'd like to create coverage reports and send to [codecov](https://codecov.io), but that was more troublesome than I first thought.

There's a [good thread](https://github.com/jprichardson/electron-mocha/issues/135) 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](https://www.npmjs.com/package/babel-plugin-istanbul) to [instrument](https://en.wikipedia.org/wiki/Instrumentation_(computer_programming)) 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](https://www.npmjs.com/package/babel-plugin-istanbul#mocha-on-nodejs-through-nyc) so I took [this solution](https://github.com/jprichardson/electron-mocha/issues/135#issuecomment-464082312) from [bennyn](https://github.com/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](https://github.com/jprichardson/electron-mocha/issues/135#issuecomment-466020462) 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](https://www.npmjs.com/package/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](https://www.npmjs.com/package/nyc#excluding-files), 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:

![](https://thepracticaldev.s3.amazonaws.com/i/8gi6wi6zbm81494rwg2d.png)

[You can see the whole implementation commit here](https://github.com/protonmail-desktop/application/commit/1308bb5adf9c3b58d75c7600eb2e8137db3467f8) and [the follow up cleanup here](https://github.com/protonmail-desktop/application/pull/236).