ยท testing

Setup TypeScript code coverage for Electron applications

This tutorial teaches you how to include all source files for code coverage reporting in an Electron app. It covers steps such as using `babel` with `electron-mocha`, registering plugins in `babel` to instrument code, and running `nyc` to create a coverage report. The article also provides code snippets and configuration files to help you implement these steps.

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.

Contents

Environment

Tested with:

  • Node.js v10.9.0
  • Electron v4.0.5

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
{
  "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
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
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist",
    "rootDir": "src",
    "target": "es5"
  },
  "exclude": ["dist", "node_modules"]
}
.nycrc.json
{
  "all": true,
  "exclude": ["**/*.test*.ts"],
  "extension": [".ts"],
  "include": ["src/**/*.ts"],
  "per-file": false,
  "reporter": ["html"]
}
after.test.ts
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

  • nyc can combine multiple coverage files (like coverage.json) into one report
  • eletron-mocha can run tests in an Electron renderer process and in an Electron main process
  • To get full code coverage, there needs to be a test run with test files for the main process (*.test.main.ts) and a second run for tests from the renderer process (*.test.renderer.ts)
  • Electron provides a process.type (can be browser or renderer) to indicate in which process the code runs
  • To have a universal after hook for both test runs, the process.type can be used in the coverage output file name
  • istanbul needs to exclude the test files, otherwise it will report code coverage for the test files too
Back to Blog