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:
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.
npm init -y
Then, install Typescript in this npm project:
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.
tsc --init
Finally, write some code for testing later.
mkdir src && touch src/divide.ts
Edit src/divide.ts
:
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:
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
:
mkdir test && touch test/divide.test.ts
Edit test/divide.test.ts
:
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
:
npm install --save-dev cross-env tsx
[!INFO] cross-env is a useful tool for setting environment variables across platforms.
Warning
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:
{
...
"scripts": {
"test": "cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'"
},
...
}
Now, you can run test by running the command below:
npm test
You will see output like:
> 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:
npm install --save-dev nyc @istanbuljs/nyc-config-typescript
Configuring Istanbul NYC
Create a .nycrc.json
and edit:
{
"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
:
{
...
"scripts": {
"coverage": "nyc npm test",
"test": "cross-env NODE_OPTIONS='--import tsx' mocha 'test/**/*.test.ts'"
},
...
}
Run the coverage test with:
npm run coverage
The output may be:
> 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
.