NestJS: Unit and E2E tests with Jest
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".
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.
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.