Table of contents

  1. 1. Environment
  2. 2. Takeaways

Learn how to include all source files for code coverage reporting in an Electron app. In the following tutorial we will create TypeScript code coverage from Electron’s main and renderer process.

Environment

Tested with:

To receive code coverage based on TypeScript source code within an Electron environment, we need to do the following:

  1. Tell electron-mocha to use babel
  2. Register @babel/preset-typescript in babel to compile our code on-the-fly
  3. Register istanbul plugin in babel to instrument our compiled code
  4. Register a after hook in mocha to write out our coverage information (provided by istanbul)
  5. Run nyc to create a HTML report from our coverage information stored in .nyc_output
package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"devDependencies": {
"@babel/core": "7.3.3",
"@babel/plugin-proposal-class-properties": "7.3.3",
"@babel/preset-env": "7.3.1",
"@babel/preset-typescript": "7.3.3",
"@babel/register": "7.0.0",
"@types/mocha": "5.2.6",
"babel-plugin-istanbul": "5.1.1",
"electron": "4.0.5",
"electron-mocha": "6.0.4",
"nyc": "13.3.0",
"typescript": "3.3.3"
},
"main": "dist/main.js",
"scripts": {
"coverage": "yarn test && nyc report",
"test": "electron-mocha --require ./babel-register.js src/**/*.test.main.ts"
},
"version": "0.0.0"
}
babel-register.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require('@babel/register')({
cache: false,
extensions: ['.ts'],
plugins: [
'@babel/proposal-class-properties',
[
'istanbul',
{
exclude: ['**/*.test*.ts'],
},
],
],
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'@babel/preset-typescript',
],
});
tsconfig.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"outDir": "dist",
"rootDir": "src",
"target": "es5"
},
"exclude": [
"dist",
"node_modules"
]
}
.nycrc.json
1
2
3
4
5
6
7
8
{
"all": true,
"exclude": ["**/*.test*.ts"],
"extension": [".ts"],
"include": ["src/**/*.ts"],
"per-file": false,
"reporter": ["html"]
}
after.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import * as fs from 'fs-extra';
import * as path from 'path';

declare global {
namespace NodeJS {
interface Global {
__coverage__: {};
}
}
}

const writeCoverageReport = (coverage: Object) => {
const outputFile = path.resolve(process.cwd(), `.nyc_output/coverage.${process['type']}.json`);
fs.outputJsonSync(outputFile, coverage);
};

after(() => {
const coverageInfo = global.__coverage__;
if (coverageInfo) {
writeCoverageReport(coverageInfo);
}
});

Takeaways