How to set up Mocha with Instanbul coverage for ESM code in 2023?

107 views Asked by At

I am almost done shaving a yak, but this one has me stumped...

My code base and the tests are ES6 code. All tests are running as expected through Mocha, but I cannot get coverage. All I get is:

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |       0 |        0 |       0 |       0 |                   
----------|---------|----------|---------|---------|-------------------

My evironment is Node v16.16.0

I had previously been using the mocha ts-node extension to run tests directly on my typescript code, which yielded coverage until things got complicated when I tried to compile to ES6 with a commonJs module dependency. This is partly responsible for me wanting to bypass ts-node completely and run tests with coverage on the compiled ES6 code. (less quirks, closer to the real world end result)

For the sake of exclusion, all sourcemapping is turned off so the test and source files are pure ES6 with no distraction.

I have followed the guidance from a few places:

All which have led to the following configs;

// package.json
"type": "module",
"scripts": {
    "test": "NODE_ENV=test nyc mocha"
},
"devDependencies": {
    "@babel/core": "^7.23.2",
    "@babel/preset-env": "^7.23.2",
    "@babel/register": "^7.22.15",
    "@istanbuljs/nyc-config-babel": "^3.0.0",
    "babel-plugin-istanbul": "^6.1.1",
    "mocha": "^10.2.0",
    "nyc": "^15.1.0",
}
// .nycrc.json
{
    "extends": "@istanbuljs/nyc-config-babel",
    "all": true,
    "include": ["./dist/backend/src/**/*.js"], //my ES6 source files
    "reporter": ["text"],
}
// .mocharc.json
{
    "file": "test/compiled/tests.backend.spec.js", // my ES6 test suite file
    "require": ["@babel/register"]
}
// .babelrc
{
    "presets": ["@babel/preset-env"],
    "plugins": ["istanbul"]
}

--------------------------- UPDATE

I copied all my ES6 code into fresh working directory and reconstructed it as a new, minimal, npm package.

The above config does then indeed function as expected.

Back to my monorepo and yak shaving, and things immediately got complicated again.

As a sanity check, I installed c8 native V8 code-coverage, and things "just worked". This reduces the likelihood that PEBCAK.

The closest I have got was that nyc wanted to register a file, but errored with;

unknown: import.meta may appear only with 'sourceType: "module"' (5:35)
Consider renaming the file to '.mjs', or setting sourceType:module or sourceType:unambiguous in your Babel config for this file.

  3 | import * as fs from 'fs';
  4 | import { log, config } from '../../typedox.mjs';
> 5 | const __filename = log.getFilename(import.meta.url);

This persisted even after;

  • re-naming all files to .mjs,
  • with and without "type":"module" in package.json
  • setting sourceType:module or sourceType:unambiguous in .babelrc
  • setting "instrument": false in .nycrc.json

I will stick with c8 as this works for me. I have exhausted my efforts to get nyc native to work through babel in a monorepo, but maybe somebody else can answer here for posterity.

0

There are 0 answers