Testes de integração com Nestjs, Jest, Supertest, Prisma e Testcontainers
Motivação
Bem, não tenho muito costume em fazer esses tipos de publicação, mas como não achei nada especifico com a stack que utilizo no meu dia a dia, então resolvi trazer esse step by step.
Nossa API
Para esse cenário de teste, resolvi criar uma API Rest utilizando o Nestjs juntamente com o Prisma para realizar a persistência dos dados no DB.
Setup para realizar os testes
Certifique-se de ter o Docker e Node rodando na sua máquina
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { PrismaClient } from '@prisma/client';
import {
PostgreSqlContainer,
StartedPostgreSqlContainer,
} from '@testcontainers/postgresql';
import { execSync } from 'child_process';
import { AppModule } from 'src/app.module';
import * as request from 'supertest';
describe('test POST /users', () => {
let prisma: PrismaClient;
let app: INestApplication;
let container: StartedPostgreSqlContainer;
beforeAll(async () => {
// iniciando o container docker
container = await new PostgreSqlContainer().start();
// configurando a URL de conexão do prisma
const urlConnection = `postgresql://${container.getUsername()}:${container.getPassword()}@${container.getHost()}:${container.getPort()}/${container.getDatabase()}?schema=public`;
// definir a URL de conexão para conexãp do prisma
process.env.DATABASE_URL = urlConnection;
// criar as tabelas definidas no prisma no banco de dados
execSync('npx prisma db push', {
env: {
...process.env,
DATABASE_URL: urlConnection,
},
});
// importar o modúlo que queremos testar
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
// criar a aplicação
app = moduleRef.createNestApplication();
// Instanciar o prisma client com a URL de conexão
prisma = new PrismaClient({
datasources: {
db: {
url: urlConnection,
},
},
});
// Iniciar a aplicação
await app.init();
});
Feito isso já temos nosso setup pronto para iniciar os testes. A biblioteca @testcontainers/postgresql vai abstrair toda parte de inicialização do banco de dados.
Casos de teste
it('deve criar um novo usuário', async () => {
// Act
const response = await request(await app.getHttpServer())
.post('/users')
.send({
email: '[email protected]',
name: 'John Doe',
});
// Assert
const userDb = await prisma.users.findFirst();
expect(response.statusCode).toBe(201);
expect(userDb.email).toBe('[email protected]');
expect(userDb.name).toBe('John Doe');
});
it('deve lançar um erro porque já existe um usuário com esse email', async () => {
// Act
const response = await request(await app.getHttpServer())
.post('/users')
.send({
email: '[email protected]',
name: 'John Doe',
});
// Assert
expect(response.statusCode).toBe(422);
});
it('deve lançar um erro porque não foram enviados os dados para criação do usuário', async () => {
// Act
const response = await request(await app.getHttpServer()).post('/users');
// Assert
expect(response.statusCode).toBe(400);
});
Depois de executarmos todos os testes...
afterAll(async () => {
// encerrar o container em execução
await container.stop();
});
Executar os testes
npm run test
Nosso terminal
Containers no docker
Links
Documentação do testcontainers para o Node: https://node.testcontainers.org/modules/postgresql/
Meu repositório no github:
https://github.com/daviArttur/nestjs-testcontainers