I'm completely new to Sinon/Jest and unit testing, so I'm kinda lost here. I tried to make a sandbox to declare all my stubs inside it but even after using sandbox.restore() the stub's call count is preserved, so my test fails in the next 'it'.
I wasn't able to stub TypeORM's objects directly, so I decided to create fake objects and I replaced TypeORM's getRepository() to get my objects.
I'm not sure if this approach is even correct but looks like my tests are working, I can assert the number of calls, and it's parameters, in the second 'it' I can expect that the error thrown equals 'Email já cadastrado' etc.
The issue is that the number of calls won't reset for the next 'it' block. So I always get an error on the second block in the line "sandbox.assert.calledOnceWithExactly(fakeConnection.getRepository, Cidades)" since it's being called twice.
Here is my test:
// Testing tool
import * as sinon from "sinon";
import { Test } from '@nestjs/testing';
// Class being tested
import { UserRepository } from "./user.repository";
// Entities
import { Senhas } from '../../output/entities/Senhas';
import { Cidades } from '../../output/entities/Cidades';
import { Usuarios } from '../../output/entities/Usuarios';
// Importing typeorm since I'm replacing some of it's methods etc
import * as typeorm from 'typeorm'
const sandbox = sinon.createSandbox();
let mockConnection;
// Simulating TypeORM's QueryRunner
const fakeQueryRunner = {
connect: sandbox.stub().returnsThis(),
startTransaction: sandbox.stub().returnsThis(),
rollbackTransaction: sandbox.stub().returnsThis(),
commitTransaction: sandbox.stub().returnsThis(),
release: sandbox.stub().returnsThis(),
manager: { save: sandbox.stub().returnsThis() },
};
// Simulating TypeORM's Connection
const fakeConnection = {
createQueryRunner: sandbox.stub().returns( fakeQueryRunner ),
getRepository: sandbox.stub().returnsThis(),
findOneOrFail: sandbox.stub().returnsThis(),
}
describe('UserRepository', function () {
let userRepository;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
UserRepository,
],
}).compile();
userRepository = module.get<UserRepository>(UserRepository);
});
describe('signUp', function () {
beforeEach(function () {
// Creating a fake method that return my object simulating TypeORM's Connection
mockConnection= sandbox.fake.returns( fakeConnection );
// Replacing TypeORM's 'getConnection' method with mine.
sandbox.replace(typeorm, 'getConnection', mockConnection);
userRepository.create = jest.fn().mockReturnValue( Usuarios );
});
afterEach(function () {
sandbox.restore();
});
it('successfully signs up the user', async function () {
fakeQueryRunner.manager.save.onCall(0).resolves(Usuarios);
fakeQueryRunner.manager.save.onCall(1).resolves(Senhas);
const result = await userRepository.signUp(mockCredentialsDto);
// Asserting that entity 'Cidades' was intanciated
const call1 = fakeConnection.getRepository.onCall(0).resolves(typeorm.Repository);
sandbox.assert.calledWith(call1, Cidades);
sandbox.assert.calledOnceWithExactly(fakeConnection.getRepository, Cidades);
// Asserting that transaction was commited
sandbox.assert.calledOnce(fakeQueryRunner.commitTransaction);
sandbox.assert.notCalled(fakeQueryRunner.rollbackTransaction);
});
it('throws a conflic exception as username already exists', async function () {
fakeQueryRunner.manager.save.onCall(0).rejects({ code: '23505' });
try {
await userRepository.signUp(mockCredentialsDto)
} catch (err) {
expect(err).toEqual(new Error('Email já cadastrado'));
}
// Asserting that entity 'Cidades' was intanciated
const call1 = fakeConnection.getRepository.onCall(0).resolves(typeorm.Repository);
sandbox.assert.calledWith(call1, Cidades);
sandbox.assert.calledOnceWithExactly(fakeConnection.getRepository, Cidades);
// Asserting that transaction was rolled back
sandbox.assert.notCalled(fakeQueryRunner.commitTransaction);
sandbox.assert.calledOnce(fakeQueryRunner.rollbackTransaction);
});
// I will make another describe block here eventually
});
Here is the method I'm testing:
async signUp(authCredentialsDto: AuthCredentialsDto): Promise<signUpMessage> {
const { nome, email, genero, dataNascimento, profissao, organizacao, atuacao, nomeCidade, uf, senha } = authCredentialsDto;
const connection = getConnection();
const user = this.create();
const senhas = new Senhas;
const cidade = await connection.getRepository(Cidades).findOneOrFail({where: { nome: nomeCidade, uf: uf } });
// Set values
user.nome = nome;
user.email = email;
user.genero = genero;
user.dataNascimento = dataNascimento;
user.profissao = profissao;
user.organizacao = organizacao;
user.atuacao = atuacao;
user.idCidade = cidade;
const salt = await bcrypt.genSalt();
senhas.senha = await this.hashPassword(senha, salt)
senhas.idUsuario2 = user;
// Make a transaction to save the data
const queryRunner = connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.manager.save(user);
await queryRunner.manager.save(senhas);
await queryRunner.commitTransaction();
} catch (error) {
if ( error.code === '23505' ) { // Usuário repetido
await queryRunner.rollbackTransaction();
throw new ConflictException('Email já cadastrado')
} else {
await queryRunner.rollbackTransaction();
throw new InternalServerErrorException;
}
} finally {
await queryRunner.release();
}
let success: signUpMessage;
return success;
}
Aucun commentaire:
Enregistrer un commentaire