Writing unit tests in TypeScript

Chirag Rupani
4 min readJul 2, 2018

--

In this story, we would be using TypeScript for unit testing along with popular frameworks: Mocha/Chai, Jasmine or Jest. You have decided the framework and want to write unit tests in TypeScript, Great! We would walk through changes required to support unit tests in TypeScript. If not, documentation of each of this libraries can be referred. Writing test cases in TypeScript is very much same as it is in JavaScript. The most important part is to do setting up so that test cases written in TypeScript can be executed using this libraries.

The source code is available at https://github.com/chiragrupani/TSUnitTestsSetup. It contains setup and examples for each of these frameworks.

The setup is very simple, we would install respective test framework and their types. We would be using ts-node (for Mocha and jasmine) and ts-jest (for Jest) to add TypeScript support. We would be using nyc for code coverage.

We would follow the conventions: Place Source JS/TS files in src folder and tests typescript files in tests folder.

Basically, it is installation of npm packages for TypeScript, Test framework (e.g. Jasmine/Mocha/Jest) and specifying test script required to execute test cases as explained further. Along with selected unit test framework package, the corresponding types also required to be installed. For executing TS tests in Node, we need to specify Scripts for test in package.json . The package.json file is located under root of project and is generated when you execute npm init.

To debug TypeScript tests, the json specified under “VS Code debug” section below in the story need to be added under configurations in launch.json which can be created by going to Debug Menu and then Add Configuration in VS Code. Below are npm commands, test script and VS code debug recipe for each framework:

Mocha/Chai

NPM Install Command

npm i -D chai mocha nyc ts-node typescriptnpm i -D @types/chai @types/mocha

Test Script

"scripts": {
"test": "mocha -r ts-node/register tests/**/*.test.ts",
"coverage": "nyc -r lcov -e .ts -x \"*.test.ts\" npm run test"
}

VS Code Debug

{
"type": "node",
"request": "launch",
"name": "Mocha Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"--no-timeouts",
"--colors",
"${file}",
"--require",
"ts-node/register"
],
"console": "integratedTerminal",
"sourceMaps": true,
"internalConsoleOptions": "neverOpen"
}

Sample Test

describe('calculate', function() {
it('add', function() {
let result = Calculator.Sum(5, 2);
expect(result).equal(7);
});
});

Jasmine

NPM Install Command

npm i -D jasmine nyc ts-node typescriptnpm i -D @types/jasmine

Test Script

"scripts": {
"test": "ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json",
"coverage": "nyc -r text -e .ts -x \"tests/*.test.ts\" npm run test"}

The jasmine.json at root directory specifies path for tests like below:

{
"spec_dir": "tests",
"spec_files": ["**/*[tT]est.ts"]
}

VS Code Debug

{
"type": "node",
"request": "launch",
"name": "Jasmine Current File",
"program": "${workspaceFolder}/node_modules/jasmine/bin/jasmine",
"args": [
"${workspaceFolder}/TSOutput/tests/${fileBasenameNoExtension}.js"
],
"preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": ["${workspaceFolder}/TSOutput/**/*.js"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}

Sample Test

describe('calculate', function() {
it('add', function() {
let result = Calculator.Sum(5, 2);
expect(result).toBe(7);
});
});

Jest

NPM Install Command

npm i -D @babel/core @babel/preset-env @babel/preset-typescript babel-jest jest typescriptnpm i -D @types/jest

Test Script

"scripts": {
"test": "jest",
"coverage": "jest --coverage"
}

VS Code Debug

{
"type": "node",
"request": "launch",
"name": "Jest Current File",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["${relativeFile}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}

Note: Test script here is just “jest”. To use TypeScript, We define config jest.config.js and babel.config.js file at location where package.json resides

jest.config.js

module.exports = {
testEnvironment: 'node',
testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
};

babel.config.js

module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};

The key is testRegex , where we are matching ts/tsx files ending with test/spec under tests folder. We are using ‘node’ in ‘testEnvironment’ since we are executing tests on Node (which makes it faster), else we would be using default ‘jsdom’ value.

Sample Test

describe('calculate', function() {
it('add', function() {
let result = Calculator.Sum(5, 2);
expect(result).toBe(7);
});

That’s all required for set up, tests can be run by executing command:

npm t

npm t is shortcut for npm run test and for getting coverage results:

npm run coverage

Adding Test Case

Before adding unit test cases, first let us understand Suite and Specs. Spec is each individual test case and contains one or many assertions. The test case passes when its expectations are true. It is generally defined (based on test framework) by using itfunctions. it contains two parameter — one is name of test case and other function containing assertion. Suite is group of related specs and generally defined using describe similar to it and contains many it functions. Sample test case above shows how it is defined for each of the framework.

Executing some code before (test initialization) and after (cleanup) each test cases, mocking external objects/services etc depends on framework, documentation for framework would contain required information.

Thanks for reading, feel free to share and tap on clap button, if you find it useful and please add comments if you need any further help in setting up TypeScript test cases or if I missed anything.

--

--

Chirag Rupani
Chirag Rupani

Written by Chirag Rupani

Full stack .Net developer, Web developer and Web Surfer.

Responses (7)