Building a Production-grade Nodejs,GraphQL and TypeScript Server - Testing and Docker
Tags: webdev, showdev, graphql, typescript
Published: 2020-05-29 06:31:06

---
title: Building a Production-grade Nodejs,GraphQL and TypeScript Server - Testing and Docker
published: true
description:  So far we have seen, How to setup and build a GraphQL and Typescript application. In this article, we will see how to test our graphql endpoints and dockerize our application.
tags: webdev,showdev,graphql,typescript
canonical_url: https://cloudnweb.dev/2020/05/nodejs-graphql-typescript-starter-part-3/
---

So far we have seen, How to setup and build a GraphQL and Typescript application. In this article, we will see how to test our graphql endpoints and dockerize our application. Building a Production-grade Nodejs,GraphQL and TypeScript Server - Testing and Docker.

[Part 1](https://cloudnweb.dev/2020/04/nodejs-graphql-typescript-starter-part-1/)

[Part 2](https://cloudnweb.dev/2020/05/nodejs-graphql-typescript-starter-part-2)

Previous article, covers how to write login query and register mutation with type-graphql. we will see how to set the graphql endpoints using jest.

Firstly, let's setup [jest](https://jestjs.io/en/) in our application.

```bash
npm i --save-dev jest
```

Well, jest is enough if it is javascript. To test a typescript application, we might need to install few more dependancies here.

```bash
npm i --save-dev @types/jest ts-jest
```

On the above code, we install jest types and ts-jest to run testing for typescript code. After that, create a config file for jest.

**jest.config.js**

```jsx
module.exports = {
  roots: ["__test__"],
  transform: {
    "^.+\\.tsx?$": "ts-jest",
  },
  testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
  moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
}
```

Firstly, we set the root directory for test files. it depends on where we create our test file directory.

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/gjh25xm6ws80b6s2qi93.png" />
</p>

After that, we try to run all the files that matches our testRegex using [ts-jest](https://www.npmjs.com/package/ts-jest) that we installed as a dependancy.

Finally, we have the moduleFileExtensions which supports the mentioned file extensions in the array.

### MongoDB setup for testing

We need to connect with database to test our graphql endpoints. to do that, we need a database setup. let's create one for testing.

create a file **db.ts** inside our test directory and add the following code,

```tsx
import * as mongoose from "mongoose"
import UserModel from "../src/UserService/UserModel"
require("dotenv").config()

// mongoose.Promise = global.Promise;

const models = {
  user: UserModel,
}

export const cleanDB = async (cb: any) => {
  await models.user.deleteMany({})
  cb()
}

export const connectToDB = async () => {
  const MONGODB_USER = process.env.MONGODB_USER || "root"
  const MONGODB_PASSWORD = process.env.MONGODB_PASS || "Root!23456"
  const connection = await mongoose.connect(
    `mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@ds237620.mlab.com:37620/project-board-app`
  )

  return connection
}

export const disconnectDB = (cb = () => {}) => {
  mongoose.disconnect(cb)
}

export const generateMongooseId = () => {
  return mongoose.Types.ObjectId()
}
```

On the above code, we have four methods. they are,

- Clean the MongoDB
- Connect with the MongoDB
- Disconnect with MongoDB
- generate Mongoose ID

Now, we have method to connect/disconnect with database. we need a way to test our graphql endpoint. to make it happen, we need to build graphql schema for testing. let build our graphql schema,

### GraphQL setup for testing

create a file **run.ts** inside test directory and add the following code,

```tsx
import { UserResolver } from "../src/UserService/UserResolver"
import { graphql, Source } from "graphql"
import { buildSchema } from "type-graphql"
import { Container } from "typedi"
import UserModel from "../src/UserService/UserModel"

export const runQuery = async (query: string, variables: any, ctx = {}) => {
  Container.set({ id: "USER", factory: () => UserModel })

  const schema = await buildSchema({
    resolvers: [UserResolver],
    emitSchemaFile: true,
    nullableByDefault: true,
    container: Container,
  })
  return graphql(schema, query, null, {}, variables)
}
```

On the above code, we build a schema just like we do in our server code and return graphql instance which is used to run graphql endpoints.

Containers are used to inject the dependancy for our graphql endpoint testing. checkout the [second part](https://cloudnweb.dev/2020/05/nodejs-graphql-typescript-starter-part-2/) to know more about dependancy injection.

finally,we came to the API testing part. i am telling you, this is an interesting part. because, it helps you to improve your code quality in some way. i personally felt that testing helps a lot in development.

### Query & Mutation testing

create a file **api/user.resolver.spec.ts** and import the required dependancies.

```tsx
const db = require("../db")
import { runQuery } from "../run"
import { GraphQLError } from "graphql"
```

If you're completely new to the world of testing, i recommend you to checkout [this](https://www.youtube.com/watch?v=7r4xVDI2vho) video.

Firstly, we need to connect with our database before running any test cases. connect with database using jest **beforeAll** method.

```tsx
beforeAll(db.connectToDB)
```

At the same time, we need to disconnect and clean the data from database after we run the test cases successfully.

```tsx
afterAll(db.disconnectDB)

afterAll(db.cleanDB)
```

Each test cases should be defined as **it** in jest or most of the testing frameworks.

```tsx
describe("Register Mutation", () => {
  beforeAll(db.connectToDB)

  afterAll(db.disconnectDB)

  afterAll(db.cleanDB)

  const registerMutation = `
mutation Register($name: String!,$email : String!,$password : String!) {
  registerUser(
  name : $name,email : $email,password: $password
  ) {
    success
    data{
      name 
      email
    }
    error
  }
}
`
  it("run successfully", async () => {
    const user = {
      name: "test",
      email: "test@gmail.com",
      password: "123456",
    }

    const response = await runQuery(registerMutation, {
      name: user.name,
      email: user.email,
      password: user.password,
    })
    expect(response).toMatchObject({
      data: {
        registerUser: {
          success: true,
          data: {
            name: user.name,
            email: user.email,
          },
          error: null,
        },
      },
    })
  })
})
```

On the above code, we have register mutation and **runQuery** which run the graphql mutation and returns the result.

```tsx
const registerMutation = `
mutation Register($name: String!,$email : String!,$password : String!) {
  registerUser(
  name : $name,email : $email,password: $password
  ) {
    success
    data{
      name 
      email
    }
    error
  }
}
`
```

you can mock the data or we can use some libraries such as [fakerjs](https://github.com/marak/Faker.js/) to mock the data.

```tsx
const user = {
  name: "test",
  email: "test@gmail.com",
  password: "123456",
}

const response = await runQuery(registerMutation, {
  name: user.name,
  email: user.email,
  password: user.password,
})
```

you can use any matchers from jest to test the result. Here, we match the result object to be the expected.

```tsx
expect(response).toMatchObject({
  data: {
    registerUser: {
      success: true,
      data: {
        name: user.name,
        email: user.email,
      },
      error: null,
    },
  },
})
```

In similar way, write a test case for login query. let's run the test cases and see the result.

![Building%20a%20Production%20grade%20Nodejs%20GraphQL%20and%20Typ%20f293f39e08204372a13477dab83a0500/testing-graphql.png](https://dev-to-uploads.s3.amazonaws.com/i/x44gxp9nrpqri0kdnpjt.png)

Now, we have test cases for our graphql server. let's dockerize our application and run our application as docker container.

## Dockerizing GraphQL,TypeScript server

I assume that you have some knowledge on what is docker and how docker works. if you're new to docker and nodejs dockerization. checkout [this](https://cloudnweb.dev/2019/10/crafting-multi-stage-builds-with-docker-in-node-js) article on dockerizing nodejs server.

Here, we are going to follow a multi-stage build on typescript,graphql server.

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/wgsm9i11ond82fxqrgi2.png" />
</p>

create a **Dockerfile** in your root directory and add the following code,

```docker
#stage1
FROM node as builder
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

#stage 2
FROM node
WORKDIR /usr/app
COPY package*.json ./
RUN npm install --production

COPY --from=builder /usr/app/dist ./dist

COPY .env .
CMD node dist/index.js
```

Let's understand what's happening on the above code.

### Stage1

1. We install the nodejs with alias name builder
2. Set **/usr/app** as the Working directory
3. Copying the package.json to the docker root directory.
4. we don't want to copy the node_modules to docker directly. it is cumbersome. instead we copy the package file and run npm install
5. Finally, we run **npm run build** to take the compiled javascript from typescript

### Stage2

1. On final docker image, we install node
2. Set **/usr/app** as working directory
3. Copying the **package.json** to the docker root directory.
4. Run **npm install** which install only the production dependancies
5. Copy all the compiled js from intermediate docker container to final container.
6. Finally, run the application using **node index.js**

Complete source code can be found [here](https://github.com/ganeshmani/graphql-typescript-server-starter)

Found any issues or Comments. Create it as issue in github [here](https://github.com/ganeshmani/graphql-typescript-server-starter/issues/new).