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.
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 in our application.
1npm 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.
1npm 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
1module.exports = {2 roots: ["__test__"],3 transform: {4 "^.+\\.tsx?$": "ts-jest",5 },6 testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",7 moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],8}
Firstly, we set the root directory for test files. it depends on where we create our test file directory.
After that, we try to run all the files that matches our testRegex using ts-jest that we installed as a dependancy.
Finally, we have the moduleFileExtensions which supports the mentioned file extensions in the array.
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,
1import * as mongoose from "mongoose"2import UserModel from "../src/UserService/UserModel"3require("dotenv").config()45// mongoose.Promise = global.Promise;67const models = {8 user: UserModel,9}1011export const cleanDB = async (cb: any) => {12 await models.user.deleteMany({})13 cb()14}1516export const connectToDB = async () => {17 const MONGODB_USER = process.env.MONGODB_USER || "root"18 const MONGODB_PASSWORD = process.env.MONGODB_PASS || "Root!23456"19 const connection = await mongoose.connect(20 `mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@ds237620.mlab.com:37620/project-board-app`21 )2223 return connection24}2526export const disconnectDB = (cb = () => {}) => {27 mongoose.disconnect(cb)28}2930export const generateMongooseId = () => {31 return mongoose.Types.ObjectId()32}
On the above code, we have four methods. they are,
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,
create a file run.ts inside test directory and add the following code,
1import { UserResolver } from "../src/UserService/UserResolver"2import { graphql, Source } from "graphql"3import { buildSchema } from "type-graphql"4import { Container } from "typedi"5import UserModel from "../src/UserService/UserModel"67export const runQuery = async (query: string, variables: any, ctx = {}) => {8 Container.set({ id: "USER", factory: () => UserModel })910 const schema = await buildSchema({11 resolvers: [UserResolver],12 emitSchemaFile: true,13 nullableByDefault: true,14 container: Container,15 })16 return graphql(schema, query, null, {}, variables)17}
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 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.
create a file api/user.resolver.spec.ts and import the required dependancies.
1const db = require("../db")2import { runQuery } from "../run"3import { GraphQLError } from "graphql"
If you're completely new to the world of testing, i recommend you to checkout this video.
Firstly, we need to connect with our database before running any test cases. connect with database using jest beforeAll method.
1beforeAll(db.connectToDB)
At the same time, we need to disconnect and clean the data from database after we run the test cases successfully.
1afterAll(db.disconnectDB)23afterAll(db.cleanDB)
Each test cases should be defined as it in jest or most of the testing frameworks.
1describe("Register Mutation", () => {2 beforeAll(db.connectToDB)34 afterAll(db.disconnectDB)56 afterAll(db.cleanDB)78 const registerMutation = `9mutation Register($name: String!,$email : String!,$password : String!) {10 registerUser(11 name : $name,email : $email,password: $password12 ) {13 success14 data{15 name16 email17 }18 error19 }20}21`22 it("run successfully", async () => {23 const user = {24 name: "test",25 email: "test@gmail.com",26 password: "123456",27 }2829 const response = await runQuery(registerMutation, {30 name: user.name,31 email: user.email,32 password: user.password,33 })34 expect(response).toMatchObject({35 data: {36 registerUser: {37 success: true,38 data: {39 name: user.name,40 email: user.email,41 },42 error: null,43 },44 },45 })46 })47})
On the above code, we have register mutation and runQuery which run the graphql mutation and returns the result.
1const registerMutation = `2mutation Register($name: String!,$email : String!,$password : String!) {3 registerUser(4 name : $name,email : $email,password: $password5 ) {6 success7 data{8 name9 email10 }11 error12 }13}14`
you can mock the data or we can use some libraries such as fakerjs to mock the data.
1const user = {2 name: "test",3 email: "test@gmail.com",4 password: "123456",5}67const response = await runQuery(registerMutation, {8 name: user.name,9 email: user.email,10 password: user.password,11})
you can use any matchers from jest to test the result. Here, we match the result object to be the expected.
1expect(response).toMatchObject({2 data: {3 registerUser: {4 success: true,5 data: {6 name: user.name,7 email: user.email,8 },9 error: null,10 },11 },12})
In similar way, write a test case for login query. let's run the test cases and see the result.
Now, we have test cases for our graphql server. let's dockerize our application and run our application as docker container.
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 article on dockerizing nodejs server.
Here, we are going to follow a multi-stage build on typescript,graphql server.
create a Dockerfile in your root directory and add the following code,
1#stage12FROM node as builder3WORKDIR /usr/app4COPY package*.json ./5RUN npm install6COPY . .7RUN npm run build89#stage 210FROM node11WORKDIR /usr/app12COPY package*.json ./13RUN npm install --production1415COPY --from=builder /usr/app/dist ./dist1617COPY .env .18CMD node dist/index.js
Let's understand what's happening on the above code.
Complete source code can be found here
Found any issues or Comments. Create it as issue in github here.
No spam, ever. Unsubscribe anytime.