Testing Typescript Project With Mocha and Istanbul NYC

Mocha is a popular JS test framework, and Istanbul is a popular JS test coverage tool. How to use them when it comes to Typescript? This post shows a simple demo.

Creating a basic TS Project

Let's create a very basic Typescript project as our demo.

First, create a directory to store this project:

1
2
mkdir ts_mocha_nyc_demo
cd ts_mocha_nyc_demo

Initialize this directory as a new npm project with the command below, which generates a package.json file with default configuration.

1
npm init -y

Then, install Typescript in this npm project:

1
2
npm install --save-dev typescript
npm install --save-dev @types/node # you may also need this

Initialize Typescript with the command below, which generates a tsconfig.json file with default configuration.

1
tsc --init

Finally, write some code for testing later.

1
mkdir src && touch src/divide.ts

Edit src/divide.ts:

1
2
3
4
export const divide = (a: number, b: number): number => {
if (b === 0) throw new Error("The divisor cannot be 0");
return a / b;
};

Setting up Mocha and Run Test

Installing Chai and Mocha

Chai is an assertion library working well with Mocha. We often use them together.

To install Chai, Mocha, and their type definitions, run the following commands:

1
2
npm install --save-dev chai @types/chai
npm install --save-dev mocha @types/mocha

Writing Test Code

Create a test directory and create a divide.test.ts for testing divide.ts:

1
mkdir test && touch test/divide.test.ts

Edit test/divide.test.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { assert, expect } from "chai";
import { divide } from "../src/divide";

describe("Division Test", () => {
it("should return 2 when divide(4, 2) called", () => {
const actualResult = divide(4, 2);
const expectedResult = 2;
assert.strictEqual(actualResult, expectedResult);
});

it("should throw error when divide(4, 0) called", () => {
expect(() => {
divide(4, 0);
}).to.throw(Error, "The divisor cannot be 0");
});
});

Running Test

Note that mocha is natively a JS test framework, and we need to configure it before we can test TS code with it.

First, install cross-env and tsx:

1
npm install --save-dev cross-env tsx

cross-env is a useful tool for setting environment variables across platforms.

I tried ts-node just like the example provided by Mocha but I encountered an ERR_UNKNOWN_FILE_EXTENSION like this. Finally I use tsx and it works.

Update package.json to be like this:

1
2
3
4
5
6
7
{
...
"scripts": {
"test": "cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'"
},
...
}

Now, you can run test by running the command below:

1
npm test

You will see output like:

1
2
3
4
5
6
7
8
9
10
11
12
13

> ts_mocha_nyc_demo@1.0.0 test
> cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'



Division Test
✔ should return 2 when divide(4, 2) called
✔ should throw error when divide(4, 0) called


2 passing (3ms)

Setting up Istanbul NYC and Run Coverage Test

Installing Istanbul NYC

To install Istanbul NYC, run:

1
npm install --save-dev nyc @istanbuljs/nyc-config-typescript

Configuring Istanbul NYC

Create a .nycrc.json and edit:

1
2
3
4
5
6
7
{
"extends": "@istanbuljs/nyc-config-typescript",
"include": ["src/**/*.ts"],
"exclude": ["test/**/*.test.ts"],
"reporter": ["html", "text", "text-summary"],
"report-dir": "coverage"
}

Running Coverage Test

Update package.json:

1
2
3
4
5
6
7
8
{
...
"scripts": {
"coverage": "nyc npm test",
"test": "cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'"
},
...
}

Run the coverage test with:

1
npm run coverage

The output may be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

> ts_mocha_nyc_demo@1.0.0 coverage
> nyc npm test


> ts_mocha_nyc_demo@1.0.0 test
> cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'



Division Test
✔ should return 2 when divide(4, 2) called
✔ should throw error when divide(4, 0) called


2 passing (2ms)

-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 85.71 | 100 | 100 |
divide.ts | 100 | 85.71 | 100 | 100 | 1
-----------|---------|----------|---------|---------|-------------------

=============================== Coverage summary ===============================
Statements : 100% ( 5/5 )
Branches : 85.71% ( 6/7 )
Functions : 100% ( 2/2 )
Lines : 100% ( 3/3 )
================================================================================

You can also see the result in a web ui by opening ./coverage/index.html.

Resources