How to Write and Run TypeScript Unit Tests with Mocha, NYC, and Lerna

This guide explains how to set up Mocha for TypeScript unit testing, configure NYC for coverage reporting, and integrate both tools within a Lerna monorepo to maintain high branch coverage across multiple packages.

Node Underground
Node Underground
Node Underground
How to Write and Run TypeScript Unit Tests with Mocha, NYC, and Lerna

Using Mocha to Write TypeScript Unit Tests

We have been writing software in TypeScript for almost two years and have accumulated experience in testing it. This article shares a practical, non‑aggressive approach that works well for us.

Mocha + TypeScript Setup

We continue to use Mocha after moving to TypeScript because it is familiar. The setup relies on two packages: @types/mocha (type definitions) and ts-node (allows Node.js to run TypeScript directly).

Typical mocha.opts file:

--require ts-node/register
test/**/*.test.ts

The ts-node/register hook enables Node.js to load TypeScript files at runtime.

In test files we import Mocha types: import 'mocha'; This gives type hints for describe and it.

Measuring Test Coverage

Our quality gate requires branch coverage above 80 %. We use NYC (the CLI for Istanbul) to collect coverage.

Running nyc mocha generates a report; we usually expose it as an npm script, e.g. npm run cov, which also works well with Lerna.

NYC configuration in package.json:

"nyc": {
  "include": [
    "src/*.ts",
    "src/**/*.ts"
  ],
  "exclude": [
    "typings",
    "dist"
  ],
  "extension": [
    ".ts"
  ],
  "require": [
    "ts-node/register"
  ],
  "reporter": [
    "json",
    "html"
  ],
  "all": true
}

After npm run cov the detailed HTML report can be opened at coverage/index.html.

Coverage in a Lerna Monorepo

When managing multiple packages with Lerna, running coverage for each package individually is cumbersome. Instead we use Lerna’s run command: nyc lerna run cov --concurrency=1 NYC spawns child processes, so invoking lerna run executes each package’s npm run cov and aggregates the results.

Top‑level NYC configuration for a monorepo:

{
  "include": [
    "packages/*/src/*.ts",
    "packages/*/src/**/*.ts"
  ],
  "exclude": [
    "**/typings",
    "**/*.d.ts",
    "**/dist",
    "**/src/index.ts",
    "**/src/domain.ts"
  ],
  "extension": [
    ".ts"
  ],
  "reporter": [
    "json",
    "html"
  ],
  "all": true
}

It is recommended to install nyc and ts-node only at the repository root to avoid version mismatches between packages.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

code coverageTypeScriptunit testingLernamochanyc
Node Underground
Written by

Node Underground

No language is immortal—Node.js isn’t either—but thoughtful reflection is priceless. This underground community for Node.js enthusiasts was started by Taobao’s Front‑End Team (FED) to share our original insights and viewpoints from working with Node.js. Follow us. BTW, we’re hiring.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.