TDD with Typescript and Jest: Starter Project
By: Hoang Dinh
Tags: Test Driven Development, Backend, Typescript, Jest, Tdd

This is the first article to set up a backend project with Typescript end Jest.

It is not a series, but I will release some kind of articles about TDD with Typescript and Jest. This means, “re” write some examples by Typescript and follow TDD style. This article will become first for every article in the same category.

Create and initialize the project

Let’s create a simple nodejs project with this command:

npm init -y

The command will generate package.json file.

Install dependencies for development

We will use Typescript in this project then typescript is the first dependency.

npm install typescript -D

-D option means typescript just use for development.

Configure TypeScript compiler

Typescript will transpile ts code to js code, the output code will follow some rules, we need to define the rules for our project.

Generate default tsconfig.json file:

npx tsc --init

tsconfig.json file will be created with some default settings. As a normal Typescript project, the config file will look like this:

{

"compilerOptions": {

"target": "es5",

"module": "commonjs",

"sourceMap": true,

"outDir": "./dist",

"rootDir": "./src",

"strict": true,

"esModuleInterop": true,

"skipLibCheck": true,

"forceConsistentCasingInFileNames": true

},

"exclude": [

"node_modules",

"**/*.spec.ts"

]

}

Add a build command

When you want to deploy your project as a normal Javascript project, you have to transpile the project to the destination Javascript code. To make it easy, let’s create an npm script to build your project. In your package.json , update scripts block:

"scripts": {

"build": "tsc",

},

From now, you can build your script by command npm run build . Actually, you have another way to do the same thing, but I think this is a common way.

Add a simple Typescript code

To make sure that you are doing it in the right way, we will create a simple example to check it.

In your project, create a file with path and name as src/calc.ts (All ts file will be stored under src folder).

class Calc {

add(a: number, b: number): number {

return a + b;

}

} export default new Calc();

Simple class with a function — add .

Run build command npm run build . If everything works well, you will see the output file at dist/calc.js

Add & Configure Jest

This is an important part because we will use Jest as a test runner for this project.

Install Jest and Jest type definition:

npm i -D jest ts-jest @types/jest

jest — Test runner, test framework

ts-jest — TypeScript preprocessor support for Jest

@types/jest — Type definition for Jest.

Configuration for Jest: Create jest.config.js file in the root of the project.

module.exports = {

roots: [

"<rootDir>/src"

],

testMatch: [

"**/__tests__/**/*.+(ts|tsx|js)",

"**/?(*.)+(spec|test).+(ts|tsx|js)"

],

transform: {

"^.+\\.(ts|tsx)$": "ts-jest"

},

collectCoverageFrom: [

"**/*.{js,jsx,ts,tsx}",

"!**/*.d.ts",

"!**/node_modules/**",

],

globals: {

"ts-jest": {

tsconfig: "tsconfig.json",

},

},

}

Finally, add a test command: We add a new command to package.json ‘s scripts block:

"test: "jest"

Simple test case

If you run npm run test it will throw an error because the project does not include any test case.

Now, we will create a test case for add function. My suggestion is to create a unit test file nearby the production file. Create src/calc.spec.ts (next by src/calc.ts ). .spec.ts to make this file is a unit test file (you can use .test.ts instead, these keywords are defined in jest.config.js ‘s testMatch )

import calc from './calc'; describe('Calc', () => {

test('should return 10 for add(6, 4)', () => {

expect(calc.add(6, 4)).toBe(10);

}); test('should return 9 for add(10, -1)', () => {

expect(calc.add(10, -1)).toBe(9);

});

});

It looks simple, add function is a pure function, then we don’t need to mock, spy... anything.

Run test again npm run test . Terminal’s result should be like:

Unit test result

That is enough for TDD starter project with Typescript and Jest, bellow sections are extra options, these options help keep the project always look clean.

Eslint

We use Eslint to formating code, keep coding standards for the project.

Install eslint and plugin

npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

Create eslint config (you can run npx eslint --init to create eslint config by answer some questions)

.eslintrc.js

Add lint command as an npm script:

"lint": "eslint ./src --ext .ts"

Husky

Husky is a small tool, that forces you to do some when you working with git.

Add husky:

npm install husky -D

Initialize husky for the project:

npx husky install

Add before commit hook: (Run command before commit) Execute npm run lint

npx husky add .husky/pre-commit "npm run lint"

Add before push hook: (Run command before push) Execute npm run test

npx husky add .husky/pre-push "npm run test"

That’s all!

Summary

I think that enough for a starter project. I also push the completed source code to Github.

In the source code, I use Codetour vscode extension, which allows you to playback guided walkthroughs of this codebase.

Thank you!