How to Set Up Testing (TDD) for Typescript Nodejs API
Tags: typescript, api, testing, node
Published: 2021-11-20 16:15:57

---
title: How to Set Up Testing (TDD) for Typescript Nodejs API
published: true
description: Guide with detailed explanation on how to Set Up Testing for a Nodejs Typescript API using Jest
tags: Typescript, API, Testing, Nodejs
//cover_image: https://direct_url_to_image.jpg
---

In this article, we will see how to set up TDD for Nodejs Typescript API.

## The benefits of writing tests

> The purpose of a test case is to determine if different features within a system are performing as expected and to confirm that the system satisfies all related standards, guidelines and customer requirements. The process of writing a test case can also help reveal errors or defects within the system.
> -- Kate Brush, [What is a Test Case? - SearchSoftwareQuality](https://searchsoftwarequality.techtarget.com/definition/test-case)

The above is the best way to describe tests. 

## Typescript
TypeScript is a strongly typed programming language that builds on JavaScript.

## Node.js
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine.

## Jest
Jest is a JavaScript Testing Framework.


### Prerequisites

- Install Nodejs https://nodejs.org
- Familiarity with Typescript or JavaScript is required

## Check if Nodejs is installed
```
node -v
```
You should have the below output, it varies on the version you install
```
v14.18.1
```

## Start the project
We will start by initializing a new nodejs application. Create a folder for your project, let call it `HelloWorld`. In the directory open your terminal and run the code

```
npm init -y
```
You are instructing Nodejs to initialize a new application and accept every question as default, this should create a `package.json` file in the directory.

Typescript is a superset of javascript, in this case, typescript still transpile to javascript before you can run and execute your code.

### Dependencies
Let's add dependencies for the application.
- Expressjs: A nodejs API framework.

To install Expressjs run
```
npm install --save express
```

### DevDependencies
Development dependencies, this is a typescript project we are required to install dependencies types as devDependencies to help nodejs with type definitions for the dependencies.
- `@types/express`
- `@types/node: This helps with type definitions for Node.js`
- `ts-node: It JIT transforms TypeScript into JavaScript, enabling you to directly execute TypeScript on Node.js without precompiling, we should run the tests without compiling our code into javascript first.`
- `jest, jest-cli: Javascript testing framework to run tests`
- `@types/jest`
- `ts-jest: A Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.`
- `supertest: HTTP assertions to help our test make API calls of GET, POST, etc`
- `@types/supertest`
- `typescript: well, this is a Typescript project`

Now let install these dependencies.

```
npm install --save-dev @types/express @types/node ts-node jest jest-cli @types/jest ts-jest supertest @types/supertest request @types/request typescript
```


## Configuration

### Typescript
To set up the typescript project we need to initialise typescript configuration, run
```
npx tsc --init
```
This will create a `tsconfig.json` file with the minimal configuration which is okay for this tutorial.

### Jest Configuration

Now we will set up jest configuration for the test environment, create a file name `jest.config.ts` and add the below code. To learn more about jest configuration visit https://jestjs.io/docs/getting-started.

```
export default {
  moduleFileExtensions: ["ts", "tsx"],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  testMatch: [
    "**/tests/**/*.spec.ts",
    "**/tests/**/*.test.ts",
  ],
  testEnvironment: "node",
};
```

A little about the properties above.

- `moduleFileExtensions: An array of file extensions your modules use`.
- `transform: This is to tell jest that we will be using a different file extension not the usual .js files, in our case we are using .ts so we passed a Regex to match our file type and a module to help handle the filetype, this is where we make use of ts-jest we installed`.
- `testMatch: This property is to tell jest the directory and/or files to run for test cases`.
- `testEnvironment: We are telling jest which environment our project is targeted for in this case we are targeting Node environment`.

## Directory
This is our proposed directory structure

<pre>
├──jest.config.ts
├──package.json
├──package-lock.json
├──tsconfig.json
├──server.ts
├──src
│   └──  app.ts
└──tests
     └── app.spec.ts
</pre>

It is preferred to structure your app directory in this format for testing.

## Now the Codes
Create a folder name `src` and create a file in the `src` folder name `app.ts` with the following code.
```
import express, { Request, Response } from 'express';
const app = express();

app.get('/', (req: Request, res: Response): Response => {
  return res.status(200).json({message: 'Hello World!'})
});

export default app;
```
### Let work through the codes
- First, we import the `express` module and types of `Request, Response`.
- Then we initialize our application with express and assign it to a variable.
- Then we call the `get method` for routing, with a callback handler for our route, this callback takes to parameter `req` type Request, `res` type Response, which returns a `Response` type. For typescript, it is recommended to type variables, parameters and function returns in your codes.
- The handler returns a response of Http status code ([Learn More about status codes here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status))  `status: 200` and a json of `message: 'Hello World!'`
- Then we export our application for testing purposes and to modularize.

Was that a lot?

Next we create another file in the root folder and name it `server.ts` containing the following code.

```
import app from './src/app';

const server = app.listen(3000, ()=> {
  console.log(`This is running on port 3000`)
})

export default server
```

This is our application entry point.

### Test
Create a directory name `tests` in the directory create a file name `app.spec.ts`

```
import request from "supertest";
import {Express} from 'express-serve-static-core';
import app from "../src/app"

let server: Express

describe('APP should say "Hello World!"', () => {
  beforeAll(() => {
    server = app;
  });

  it('should return 200',  (done) => {
    request(server)
      .get('/')
      .expect(200)
      .end((err, res) => {
        if (err) return done(err)
        expect(res.body).toMatchObject({'message': `Hello World!`})
        done()
      })
  });
});
```
#### Let walk through the codes
- We import the `supertest` module and assign a variable name `request`.
- Import the Express interface
- We then import our app
- Then we declare a variable `server` with the type of Express without assigning any value to
- We describe our test suite for a test block, `describe` is a jest global function that accepts a `string` and a `callback`. 
- We passed a description of the test suite with a string `APP should say "Hello World!"`.
- In the `callback` scope we call another global function `beforeAll` which accepts a `callback`, this is to tell jest that we will want to run a block of code before the suite run its tests. In this case, we want to first assign a value to our declared variable `server` which will be to assign the app that we have imported so we can run our tests.
- Then we call another global function `it` which is a test closure that takes two parameters a `name` and a `callback`.
- The name of our test closure is **should return 200**.
- We then pass a `done` callback as a parameter for the closure callback
- We call `request` and pass the `server` variable to run our app in the test scope.
- We call the get method and pass `'/'` route. In this case, we are running HTTP GET Method to our application on the route `'/'`.
- We expect the HTTP GET Method should return 200 Ok status and return the message `'meesage':'Hello World!'`
- We call `end` method which takes a callback with two parameters of `error` and `respond`
- We check if the test has error then we return the `done` method with the `error` from the test if otherwise which means the test runs successfully, so we call the `expect` global method which we check `body` property from the `respond` parameter to match our expected result.
- Then we finally call `done` method to tell jest we are through with this suite.

## Before we are done
And finally, we need a way to run our test, so edit the `package.json` file in the scripts section change `test` property. The scripts section should look something like this.

```
...
  "scripts": {
    "dev": "ts-node server.ts",
    "test": "jest --verbose"
  },
...
```

Now when you run 
```
npm run test
```
You see result like the screenshot below.

![Image of a successful test](https://cdn.hashnode.com/res/hashnode/image/upload/v1635543032710/oiW2stbE_.png)

Let say we change the return value in `app.ts` file from `Hello World!` to `World Hello` you should see a failed test like the screenshot below.

![Image of a failed test](https://cdn.hashnode.com/res/hashnode/image/upload/v1635543262177/LxvCByqYq.png)

## Conclusion
Writing test could mean to write more code but a few lines are worth the hours it will save. I'm a Full Stack developer using React, React Native and Nodejs with Typescript.

Feel free to put questions or suggestion in the comment or you can also reach out on Twitter [iNidAName](https://twitter.com/inidaname)