You are on page 1of 23

NestJS: Unit and E2E tests with Jest

exFabrica · Follow
3 min read · Jun 8, 2022

Listen Share

Welcome back!

Our APIs work but we didn’t implement any tests to validate its behavior and
avoid possible regressions. If you remember, each time we used the CLI, NestJS
made for us all files to tests services, controllers and APIs (with E2E tests). So, we
are going to tests layer by layer and begin by unit tests on service layer.

The tests on service layer should focus on interactions with the TypeOrm
repository. So the first step is to mock the repository “InventoryItem”. NestJS has
the solution and proposes a function to do that. You have to import:

import { getRepositoryToken } from '@nestjs/typeorm';


The “getRepositoryToken” function allows us to get a fake repository (but keep the
“InventoryItem” type). It simulates all functions that the real repository have. To
implement our first unit test, we need to create a fake collection with fake
“InventoryItem”.

1 import { InventoryItem } from '@app/shared/entities/inventory.item.entity';


2 import { InventoryItemProfile } from '@app/shared/profiles/inventory.item.profile'
3 import { Test, TestingModule } from '@nestjs/testing';
4 import { getRepositoryToken } from '@nestjs/typeorm';
5 import { Repository } from 'typeorm';
6 import { InventoryService } from './inventory.service';
7
8 describe('InventoryService', () => {
9 let service: InventoryService;
10 let inventoryItemsRepository: Repository<InventoryItem>;
11
12 beforeEach(async () => {
13 const module: TestingModule = await Test.createTestingModule({
14 imports: [],
15 providers: [
16 InventoryService,
17 {
18 provide: getRepositoryToken(InventoryItem),
19 useClass: Repository,
20 },
Open
21 in app InventoryItemProfile Sign up Sign In
22 ],
23 }).compile();
24
25 service = module.get<InventoryService>(InventoryService);
26 inventoryItemsRepository = module.get<Repository<InventoryItem>>(getRepositoryToken
27 });
28
29 it('should be defined', () => {
30 expect(service).toBeDefined();
31 });
32
33
34 describe("Method findAll", () => {
35 it('it should return 2 items', async () => {
36 jest.spyOn(inventoryItemsRepository, 'find').mockResolvedValueOnce(ITEMS);
37 const result = await service.findAll();
37 const result = await service.findAll();
38 expect(result.length).toEqual(2);
39 });
40 it('it must generate an error, findAll return an error', async () => {
41 jest.spyOn(inventoryItemsRepository, 'find').mockImplementation(() => { throw
42 try {
43 await service.findAll();
44 }
45 catch (err) {
46 expect(err.message).toContain("findAll error: async error");
47 }
48 });
49 });
78
50 });
51
52 const ITEMS: InventoryItem[] = [
53 {
54 "id": 1,
55 "name": "My First Item",
56 "description": "The description of the first item",
57 "powerlevel": 1
58 },
59 {
60 "id": 2,
61 "name": "Orc Power Shield",
62 "description": "This Shield from ORC tribe is very resistant and heavy",
63 "powerlevel": 30
64 }
65 ]

inventory.service.spec.ts hosted with by GitHub view raw


We developed two unit tests for the “findAll” function : one to test the nominal
case and another to test a common error. Notice the “jest.spyOn” function to
simulate the repository call.

Next, we can look at the controllers unit tests:

All controller tests must focus on the “InventoryService” service, so we have to


mock the service, for that, we use the same method as for the service unit tests.

1 import { InventoryItem } from '@app/shared/entities/inventory.item.entity';


2 import { InventoryService } from '@app/shared/services/inventory/inventory.service'
3 import { Test, TestingModule } from '@nestjs/testing';
4 import { ReaderController } from './reader.controller';
5
6 describe('ReaderController', () => {
7 let readerController: ReaderController;
8 let service: InventoryService;
9
10 beforeEach(async () => {
11 const app: TestingModule = await Test.createTestingModule({
12 imports: [],
13 controllers: [ReaderController],
14 providers: [
15 {
16 provide: InventoryService,
17 useFactory: () => ({
18 findAll: jest.fn(() => Promise.resolve(ITEMS))
19 })
20 }],
21 }).compile();
22
23 readerController = app.get<ReaderController>(ReaderController);
24 service = app.get<InventoryService>(InventoryService);
25 });
26
27 describe("Api findAll", () => {
28 it("it calling findAll method", async () => {
29 const items: InventoryItem[] = await readerController.findAll();
30 expect(items).toBeDefined();
31 expect(items.length).toEqual(2);
32 })
33
34 it("if calling findAll and receive a specific error", async () => {
35 jest.spyOn(readerController, 'findAll').mockImplementation(() => { throw new
36 try {
37 await readerController.findAll();
38 }
39 catch (err) {
40 expect(err).toBeDefined();
41 expect(err.message).toEqual("async error");
42 }
43 });
44 });
45 });
46
47 const ITEMS: InventoryItem[] = [
48 {
49 "id": 1,
50 "name": "My First Item",
51 "description": "The description of the first item",
52 "powerlevel": 1
53 },
54 {
55 "id": 2,
56 "name": "Orc Power Shield",
57 "description": "This Shield from ORC tribe is very resistant and heavy",
58 "powerlevel": 30
58 "powerlevel": 30
59 }
60 ]

reader.controller.spec.ts hosted with by GitHub view raw


In the Reader API, we need to test only the “findAll” method while the Writer API
will take care of the “create”, “update”, and “delete”. They will share the same
service mock.
No particular difficulty to implement the tests once we have the mocked service.

Finally, let’s move on to the E2E tests:

Since the goal is really to test the API calls, we have to set up new configuration
elements. Open a terminal and add the following library:

> npm install @nestjs/config


This module allows us to use and configure the configuration of NestJS. First of
all, we must add in section “imports” if the shared library module to this new
library.

ConfigModule.forRoot({ isGlobal: true }),

At the root of the solution, we add a NodeJS “.env” file. This is the entry point for
our NestJS configuration. Inside this file, we add 2 keys:

DATABASE_NAME_FOR_DEV = “sqlite”

DATABASE_NAME_FOR_TEST = “dbE2E”

Then we need to update the configuration step in the “shared.module.ts”


declaration. We are going to use a construction “factory” and pass it the
“configModule” module as well as the “configService” configuration service to
retrieve our 2 configuration keys. NestJS is responsible for making the link
between the configuration of NodeJS through the “.env” file and our service layer.
Now, we are able to switch between our development and tests database.

Back to our E2E files (Test folder in each applications). A required action is
mandatory to continue, we need to update “jest-e2e.json” file and add a
“moduleNameMapper” section in the json to declare the shared library.
Once done, our tests will compile without error.

Notice that the creation of the test database and the insertion of data with a SQL
request: with this method, you add a full set of data to create a real test schema.
The database is created each time you launch the E2E tests.

Look at this line:

request(app.getHttpServer()).get(‘/inventory’).

This asynchronous function allows us to query our test database, it returns the
HTTP response, so we can validate the data returned and finish our E2E tests.

For the “writer” the approach is the same but we will use POST, PUT and DELETE
to test the different parts of the API.
Mission complete!

Our tests are implemented ! We can think about the next part : DTO objects with
Automapper.

Back to previous story: The code first approach with TypeOrm.

Back to the table of contents: NestJS: a powerful technical stack!

See U!
Nestjs Nodejs Api Development Javascript Development Typescript

Follow

Written by exFabrica
97 Followers

More from exFabrica

exFabrica
exFabrica

NestJS: DTO with Automapper


Welcome back!

4 min read · Jun 14, 2022

131 2

exFabrica

NestJS: The code first approach with TypeOrm


Welcome back!

6 min read · Jun 8, 2022

5
exFabrica

NestJS: Installation and creation of a monorepo project with CQRS


architecture.
NestJS copies some internal concepts from Angular, from which it takes the MVC
architecture and its main patterns, TypeScript for…

5 min read · Jun 2, 2022

6 1

exFabrica

Strapi: How to create a set of components and inject them to Strapi


Admin website?
Welcome back!
5 min read · Apr 25, 2022

43 1

See all from exFabrica

Recommended from Medium

Razvan L in Dev Genius

Write Unit Tests with Jest in Node.js


Jest is a clean and concise JavaScript testing framework developed and maintained by
Facebook.

· 4 min read · Jan 5

56
Daniel Delimata

Cucumber in the Typescript


In this post we will go through setting up the project in Typescript with Selenium/Playwright,
Cucumber and Allure.

· 11 min read · Mar 6

11

Lists

Stories to Help You Grow as a Software Developer


19 stories · 42 saves
Software Surplus in Level Up Coding

How To Write Tests For Node Express Routes (With Auth Example)
A guide to writing comprehensive unit tests using Jest plus Typescript with examples

· 7 min read · Dec 19, 2022

180 2

alexander grossmann in JavaScript in Plain English

Level up you’re UI Testing with Cypress


You will learn what cypress is why to use cypress and how to use cypress for quality
assurance in your next vue js or other JavaScript…
· 7 min read · Jan 9

Marcin in JavaScript in Plain English

How to Prioritize Test Cases in End-to-End Testing


Adding end-to-end (E2E) tests to your application from scratch is a lot of work. Building a
complete test suite will be a long project, so…

· 4 min read · Mar 24

8
Enes Başpınar in Trendyol Tech

Jest Mocking — Part 1: Function


In this article series, we will take a look at how to mock with Jest.

13 min read · Jan 17

236

See more recommendations

You might also like