Configuring nyc, tape and ts-node

 ⋅ 1 min read

I've been writing a lot of TypeScript in the last few years, and have come to love it for writing my Node.js projects.

My workflow

For tests, I religiously use tape because unlike mocha, it does not need a test-runner — tape tests can be run as regular Node modules. tape also doesn't pollute global with "magic" functions, which mocha does with abandon.

nyc is pretty much the only choice for code coverage in Node-land. It is a CLI-wrapper around instanbuljs and is regularly maintained.

I prefer to use ts-node for tests as it lets me rapidly test without having to run tsc every time to transpile tests to JS.

The problem

One of the biggest pain points in using this combination is correctly configuring them.

Most of the folks that use these same tools run into weird coverage issues (inconsistent results across runs, 0% coverage, runtime errors. etc.)

A Google search lands in istanbuljs/nyc/issues #497, which has conflicting information. Not to mention the officially recommended config preset nyc-config-typescript had an issue that was only just fixed.

The solution

After a lot of trial and error, here's what works best.

  1. nyc config — I'd recommend saving this in .nycrc.json in your project's root directory. Saving it as a .json file gives you better syntax highlighting in the editor of your choice.

        "extension": [
        "require": [
        "exclude": [
        "reporter": [
        "cache": false
  2. npm scripts —

        "scripts": {
            "test": "tape -r ts-node/register/transpile-only test/**/*.test.ts test/*.test.ts",
            "coverage": "nyc tape -r ts-node/register/transpile-only test/**/*.test.ts  test/*.test.ts",

You can replace ts-node/register/transpile-only with ts-node/register if you run into unexpected issues, but in most cases it works and is ~50% faster in my experience.

Happy testing! 🥳