Testing entire flows
It's time to finally implement our more realistic, e2e tests.
Now, we can focus entirely on the test file. Back to it, first let's replace beforeEach() with beforeAll(), so that the app is initialized just once instead of before each test. Let's also add an afterAll() call at the bottom to clean up resources, such as close the database connection, etc.
afterAll(async () => {
await app.close();
});Here, the 5 routes will be hit sequentially in the same database. Ergo, it will be verified if when:
Creating a
user, it is created successfullySearching for all
users, there is a single oneSearching for this
user, it is foundUpdating this
user, the field is changedRemoving this
user, it no longer exists
To help us, let's put at the top of the file:
A fake
createUserDtoA fake
updateUserDtoAn
expectedUser
const createUserDto: CreateUserDto = {
name: faker.person.firstName(),
email: faker.internet.email(),
phone: '85988888888',
password: 'AAaa11!!',
};
const updateUserDto: UpdateUserDto = {
name: faker.person.firstName(),
};
const expectedUser = {
id: 1,
...createUserDto,
role: Role.USER,
} as User;Now, let's change the name of the describe() to the resource being tested and its base path.
'Users [/users]'In the imports of the module, let's add the ConfigModule so we can access the environment variables, and use the validation schema for testing. We should also specify the path for the appropriate .env file. We'll also connect to the database right after it.
ConfigModule.forRoot({
validationSchema: TEST_ENV_VALIDATION_SCHEMA,
envFilePath: '.env.test.local',
}),
TypeOrmModule.forRootAsync(testDatabaseConfig.asProvider()),And lastly, in the providers, enable the ValidationPipe and the NotFoundExceptionFilter globally.
{
provide: APP_PIPE,
useValue: new ValidationPipe(VALIDATION_PIPE_OPTIONS),
},
{
provide: APP_FILTER,
useClass: NotFoundExceptionFilter,
},Now, remember that writing style we used in that default test? Let's then continue to use it and everything will be much simpler.
Beginning with the test for create(), we shall:
Access the /users route with POST
While sending the
createUserDtoin thebodywithsend()
Check if:
The
statusis CREATEDThe
bodymatches theexpectedUser
it('Create [POST /]', async () => {
const response = await request(server).post('/users').send(createUserDto);
const { status } = response;
const body = response.body as User;
expect(status).toBe(HttpStatus.CREATED);
expect(body).toMatchObject(expectedUser);
});In findAll(), we:
Access the /users route with GET
Check if:
The
statusis OKThe
bodycontains a single elementIt matches the
expectedUser
it('Find all [GET /]', async () => {
const response = await request(server).get('/users');
const { status } = response;
const body = response.body as User[];
expect(status).toBe(HttpStatus.OK);
expect(body.length).toBe(1);
expect(body[0]).toMatchObject(expectedUser);
});In findOne(), there's nothing new.
it('Find one [GET /:id]', async () => {
const response = await request(server).get('/users/1');
const { status } = response;
const body = response.body as User;
expect(status).toBe(HttpStatus.OK);
expect(body).toMatchObject(expectedUser);
});In update(), we just check if the name was altered. The findOne() is also used for checking this.
it('Update [PATCH /:id]', async () => {
const response = await request(server).patch('/users/1').send(updateUserDto);
const { status } = response;
const body = response.body as User;
expect(status).toBe(HttpStatus.OK);
expect(body.name).toBe(updateUserDto.name);
const findOneResponse = await request(server).get('/users/1');
const findOneBody = findOneResponse.body as User;
expect(findOneBody.name).toBe(updateUserDto.name);
});Finally, in remove(), we also check if a findOne() call will result in the status NOT FOUND.
it('Remove [DELETE /:id]', async () => {
const response = await request(server).delete('/users/1');
const { status } = response;
expect(status).toBe(HttpStatus.OK);
const findOneResponse = await request(server).get('/users/1');
expect(findOneResponse.status).toBe(HttpStatus.NOT_FOUND);
});And we're done! Just remember to delete that default test and then run the e2e tests.
yarn test:e2eCommit - Implementing e2e tests
Last updated