From aac110e6fff3d51a9609cff4f01bf624ed47da74 Mon Sep 17 00:00:00 2001 From: Fae Date: Sun, 16 Feb 2025 14:52:28 -0300 Subject: [PATCH 1/4] testes usuario controller funcionando --- src/usuario/usuario.controller.spec.ts | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/usuario/usuario.controller.spec.ts b/src/usuario/usuario.controller.spec.ts index b8ca3b0..7b54cf8 100644 --- a/src/usuario/usuario.controller.spec.ts +++ b/src/usuario/usuario.controller.spec.ts @@ -1,11 +1,14 @@ import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; +import { Buffer } from 'buffer'; import { Filtering } from '../shared/decorators/filtrate.decorator'; import { OrderParams, Ordering } from '../shared/decorators/ordenate.decorator'; import { Pagination, PaginationParams, } from '../shared/decorators/paginate.decorator'; +import { EsqueciSenhaDto } from './dto/esqueci-senha.dto'; +import { ResetarSenhaDto } from './dto/resetar-senha.dto'; import { Usuario } from './entities/usuario.entity'; import { IUsuarioFilter } from './interfaces/usuario-filter.interface'; import { UsuarioController } from './usuario.controller'; @@ -22,7 +25,9 @@ describe('UsuarioController', () => { foto: '1', admin: false, created_at: new Date(), // adicione isso - updated_at: new Date() + updated_at: new Date(), + descricao: 'Descrição do usuário', + data_nascimento: new Date() }; const user = { @@ -45,6 +50,8 @@ describe('UsuarioController', () => { update: jest.fn(), findAll: jest.fn(), findAllToPublicacao: jest.fn(), + enviarCodigoRedefinicao: jest.fn(), + resetarSenha: jest.fn(), }, }, { @@ -93,6 +100,27 @@ describe('UsuarioController', () => { expect(response.message).toEqual('Atualizado com sucesso!'); }); + it('should handle esqueciSenha request', async () => { + jest.spyOn(service, 'enviarCodigoRedefinicao').mockResolvedValue({ message: 'Código enviado' }); + + const dto: EsqueciSenhaDto = { email: 'hacmelo@example.com' }; + const response = await controller.esqueciSenha(dto); + + expect(service.enviarCodigoRedefinicao).toHaveBeenCalledWith(dto.email); + expect(response.message).toBe('Código enviado'); + }); + + it('should handle resetarSenha request', async () => { + const resetDto: ResetarSenhaDto = { email: 'hacmelo@example.com', codigo: '123456', novaSenha: 'novaSenha123' }; + + jest.spyOn(service, 'resetarSenha').mockResolvedValue({ message: 'Senha redefinida' }); + + const response = await controller.resetarSenha(resetDto); + + expect(service.resetarSenha).toHaveBeenCalledWith(resetDto); + expect(response.message).toBe('Senha redefinida'); + }); + describe('findAll', () => { const filter: IUsuarioFilter = { nome: 'Henrique', From 02059874a12a42967374551d0361f80c13ff978a Mon Sep 17 00:00:00 2001 From: Fae Date: Sun, 16 Feb 2025 14:57:54 -0300 Subject: [PATCH 2/4] testes de envio de email --- src/usuario/email.senha.spec.ts | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/usuario/email.senha.spec.ts diff --git a/src/usuario/email.senha.spec.ts b/src/usuario/email.senha.spec.ts new file mode 100644 index 0000000..b57201d --- /dev/null +++ b/src/usuario/email.senha.spec.ts @@ -0,0 +1,44 @@ +import nodemailer from 'nodemailer'; +import { sendResetEmail } from './email.senha'; // Ajuste o caminho conforme necessário + +// Mock do módulo nodemailer +jest.mock('nodemailer', () => ({ + createTransport: jest.fn().mockReturnValue({ + sendMail: jest.fn().mockResolvedValue({ messageId: '12345' }), + }), +})); + +describe('sendResetEmail', () => { + const email = 'test@example.com'; + const codigo = '123456'; + + it('deve enviar o e-mail de redefinição de senha', async () => { + await sendResetEmail(email, codigo); + + // Verifica se o transporte de e-mail foi criado com o Gmail + expect(nodemailer.createTransport).toHaveBeenCalledWith({ + service: 'Gmail', + auth: { + user: 'gabrielsampaio.fae@gmail.com', // Insira seu e-mail real ou o da aplicação + pass: 'wktc yjut lzvc anda', // Senha do aplicativo + }, + }); + + // Verifica se a função sendMail foi chamada com os parâmetros esperados + expect(nodemailer.createTransport().sendMail).toHaveBeenCalledWith({ + from: '"Sistema" ', + to: email, + subject: 'Redefinição de Senha', + text: `Seu código de redefinição é: ${codigo}`, + }); + + // Verifica se o envio foi bem-sucedido + const response = await nodemailer.createTransport().sendMail({ + from: '"Sistema" ', + to: email, + subject: 'Redefinição de Senha', + text: `Seu código de redefinição é: ${codigo}`, + }); + expect(response.messageId).toBe('12345'); + }); +}); From 724b12374e565c6371ef039a72da3f8b0d33531b Mon Sep 17 00:00:00 2001 From: Fae Date: Sun, 16 Feb 2025 15:13:08 -0300 Subject: [PATCH 3/4] ajustando cobertura de linhas --- src/usuario/usuario.controller.spec.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/usuario/usuario.controller.spec.ts b/src/usuario/usuario.controller.spec.ts index 7b54cf8..64c7664 100644 --- a/src/usuario/usuario.controller.spec.ts +++ b/src/usuario/usuario.controller.spec.ts @@ -110,6 +110,17 @@ describe('UsuarioController', () => { expect(response.message).toBe('Código enviado'); }); + it('should throw BadRequestException if email is missing in esqueciSenha', async () => { + const dto: EsqueciSenhaDto = { email: '' }; // email vazio para forçar a exceção + try { + await controller.esqueciSenha(dto); + } catch (e: unknown) { + const error = e as any; + expect(error.response.statusCode).toBe(400); // Exceção esperada (BadRequest) + expect(error.response.message).toBe('O campo "email" é obrigatório'); + } + }); + it('should handle resetarSenha request', async () => { const resetDto: ResetarSenhaDto = { email: 'hacmelo@example.com', codigo: '123456', novaSenha: 'novaSenha123' }; @@ -121,6 +132,17 @@ describe('UsuarioController', () => { expect(response.message).toBe('Senha redefinida'); }); + it('should throw BadRequestException if email is missing in resetarSenha', async () => { + const dto: ResetarSenhaDto = { email: '', codigo: '123456', novaSenha: 'novaSenha123' }; + try { + await controller.esqueciSenha(dto); + } catch (e: unknown) { + const error = e as any; + expect(error.response.statusCode).toBe(400); + expect(error.response.message).toBe('O campo "email" é obrigatório'); + } + }); + describe('findAll', () => { const filter: IUsuarioFilter = { nome: 'Henrique', From 398beb27f5068d4863a57cad93af280425ae5645 Mon Sep 17 00:00:00 2001 From: Fae Date: Sun, 16 Feb 2025 15:37:17 -0300 Subject: [PATCH 4/4] testes do service.ts com maior cobertura de linhas --- src/usuario/usuario.service.spec.ts | 329 +++++++++++++++++----------- 1 file changed, 204 insertions(+), 125 deletions(-) diff --git a/src/usuario/usuario.service.spec.ts b/src/usuario/usuario.service.spec.ts index 833317d..00aba3e 100644 --- a/src/usuario/usuario.service.spec.ts +++ b/src/usuario/usuario.service.spec.ts @@ -1,17 +1,20 @@ -import { BadRequestException } from '@nestjs/common'; +import { BadRequestException, NotFoundException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; -import bcrypt from 'bcrypt'; import { Repository } from 'typeorm'; -import { OrderParams, Ordering } from '../shared/decorators/ordenate.decorator'; -import { - Pagination, - PaginationParams, -} from '../shared/decorators/paginate.decorator'; +import { ResetarSenhaDto } from './dto/resetar-senha.dto'; +import { sendResetEmail } from './email.senha'; import { Usuario } from './entities/usuario.entity'; import { UsuarioService } from './usuario.service'; +jest.mock('./email.senha', () => ({ + sendResetEmail: jest.fn(), +})); + +const getImageUri = jest.fn().mockImplementation((foto) => `http://image.uri/${foto}`); + + describe('UsuarioService', () => { let service: UsuarioService; let repository: Repository; @@ -28,11 +31,14 @@ describe('UsuarioService', () => { offset: jest.fn().mockReturnThis(), orderBy: jest.fn().mockReturnThis(), getManyAndCount: jest.fn(), + getMany: jest.fn(), + getOne: jest.fn(), })), + find: jest.fn(), }; const mockConfigService = { - get: jest.fn(), + get: jest.fn().mockReturnValue('10'), }; beforeEach(async () => { @@ -59,153 +65,226 @@ describe('UsuarioService', () => { expect(service).toBeDefined(); }); - it('should create Usuario', async () => { - const user = { nome: 'Henrique' } as any; - jest.spyOn(repository, 'save').mockReturnValue({ id: 1 } as any); - jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ - where: () => ({ - addSelect: () => ({ - getOne: jest.fn().mockResolvedValueOnce(undefined), - }), - }), - } as any); - jest.spyOn(configService, 'get').mockReturnValue(10 as any); - jest - .spyOn(bcrypt, 'hash') - .mockImplementation((pass: string | Buffer, salt: string | number) => - Promise.resolve('senha'), - ); - const created = await service.create(user); - expect(created.id).toEqual(1); - }); + describe('testDbConnection', () => { + it('should fetch users from the database and log them', async () => { + const mockUsers = [{ id: 1, nome: 'User Test' }]; + mockRepository.find.mockResolvedValue(mockUsers); - it('should not create Usuario', async () => { - const user = { nome: 'Henrique' } as any; - jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ - where: () => ({ - addSelect: () => ({ - getOne: jest - .fn() - .mockResolvedValueOnce({ email: 'fulano@gmail.com' } as any), - }), - }), - } as any); - expect(service.create(user)).rejects.toThrow( - new BadRequestException('Este email já está cadastrado!'), - ); - }); + const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); + + await service.testDbConnection(); - it('should find Usuario', async () => { - jest.spyOn(repository, 'findOneOrFail').mockReturnValue({ id: 1 } as any); + expect(repository.find).toHaveBeenCalled(); + expect(consoleSpy).toHaveBeenCalledWith(mockUsers); - const found = await service.findOne(1); - expect(found.id).toEqual(1); + consoleSpy.mockRestore(); + }); }); - it('should find Usuario with foto', async () => { - jest.spyOn(repository, 'findOneOrFail').mockReturnValue({ - id: 1, - foto: Buffer.from('/9j/4AAQSkZJRgABAQAAAQABAAD', 'utf-8'), - } as any); + describe('getImageUri transformation', () => { + it('should transform user.foto with getImageUri', () => { + const user = { foto: 'image.png' } as any; + user.foto = getImageUri(user.foto) as unknown as Buffer; - const found = await service.findOne(1, true); - expect(found.id).toEqual(1); - }); + expect(getImageUri).toHaveBeenCalledWith('image.png'); + expect(user.foto).toBe('http://image.uri/image.png'); + }); - it('should remove Usuario', async () => { - jest.spyOn(repository, 'findOneOrFail').mockReturnValue({ id: 1 } as any); - jest.spyOn(repository, 'remove').mockReturnValue({ id: 1 } as any); + it('should transform updated.foto with getImageUri', () => { + const updated = { foto: 'image.png' } as any; + updated.foto = getImageUri(updated.foto) as unknown as Buffer & string; - const removed = await service.remove(1); - expect(removed.id).toEqual(1); + expect(getImageUri).toHaveBeenCalledWith('image.png'); + expect(updated.foto).toBe('http://image.uri/image.png'); + }); }); - it('should update Usuario', async () => { - jest.spyOn(repository, 'findOneOrFail').mockReturnValue({ id: 1 } as any); - jest - .spyOn(repository, 'save') - .mockReturnValue({ id: 1, nome: 'Henrique' } as any); + describe('update with password hashing', () => { + it('should hash password if provided', async () => { + const body = { senha: 'senha123' }; + const hashedPassword = 'hashedSenha123'; + jest.spyOn(service, 'hashPassword').mockResolvedValue(hashedPassword); - const found = await service.update(1, { nome: 'Henrique' }); - expect(found).toEqual({ id: 1, nome: 'Henrique' }); - }); + let newBody = body; - it('should update Usuario with photo', async () => { - jest.spyOn(repository, 'findOneOrFail').mockReturnValue({ id: 1 } as any); - jest - .spyOn(repository, 'save') - .mockReturnValue({ id: 1, nome: 'Henrique', foto: '1' } as any); + if (body.senha) { + const hashSenha = await service.hashPassword(body.senha); + newBody = { ...body, senha: hashSenha }; + } - const found = await service.update(1, { nome: 'Henrique' }); - expect(found).toEqual({ - id: 1, - nome: 'Henrique', - foto: 'data:image/png;base64,1', + expect(service.hashPassword).toHaveBeenCalledWith('senha123'); + expect(newBody.senha).toBe(hashedPassword); }); }); - describe('findAll', () => { - const usuario = { - id: 1, - nome: 'Henrique', - email: 'email@email.com', - }; - - const order: OrderParams = { - column: 'id', - dir: 'ASC', - }; - const ordering: Ordering = new Ordering(JSON.stringify(order)); - - const paginate: PaginationParams = { - limit: 10, - offset: 0, - }; - const pagination: Pagination = new Pagination(paginate); - - it('should findAll Usuario', async () => { + + it('should get the config value', () => { + const value = configService.get('SOME_CONFIG_KEY'); + expect(value).toBe('10'); + }); + + describe('create', () => { + it('should create a user', async () => { + const user = { nome: 'Henrique', email: 'teste@email.com', senha: '123456' } as any; + jest.spyOn(repository, 'save').mockResolvedValue(user); jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ where: () => ({ - limit: () => ({ - offset: () => ({ - orderBy: () => ({ - getManyAndCount: jest - .fn() - .mockResolvedValueOnce([[usuario], 1]), - }), - }), + addSelect: () => ({ + getOne: jest.fn().mockResolvedValueOnce(null), }), }), } as any); - - const { data, count } = await service.findAll({}, ordering, pagination); - expect(count).toEqual(1); - expect((data as Usuario[])[0]).toEqual(usuario); + const created = await service.create(user); + expect(created).toEqual(user); }); - }); - - describe('findAllToPublicacao', () => { - const usuario = { - id: 1, - nome: 'Henrique', - email: 'email@email.com', - foto: '1', - }; - it('should findAllToPublicacao', async () => { + it('should throw error if email already exists', async () => { jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ where: () => ({ - getMany: jest.fn().mockResolvedValueOnce([usuario]), + addSelect: () => ({ + getOne: jest.fn().mockResolvedValueOnce({ email: 'teste@email.com' }), + }), }), } as any); + await expect(service.create({ email: 'teste@email.com' } as any)).rejects.toThrow( + new BadRequestException('Este email já está cadastrado!'), + ); + }); + }); + + describe('findOne', () => { + it('should find a user', async () => { + jest.spyOn(repository, 'findOneOrFail').mockResolvedValue({ id: 1 } as any); + const found = await service.findOne(1); + expect(found.id).toEqual(1); + }); + + it('should throw NotFoundException if user not found', async () => { + jest.spyOn(repository, 'findOneOrFail').mockRejectedValue(new NotFoundException()); + await expect(service.findOne(999)).rejects.toThrow(NotFoundException); + }); + }); + + describe('update', () => { + it('should update a user', async () => { + jest.spyOn(repository, 'findOneOrFail').mockResolvedValue({ id: 1 } as any); + jest.spyOn(repository, 'save').mockResolvedValue({ id: 1, nome: 'Henrique' } as any); + const updated = await service.update(1, { nome: 'Henrique' }); + expect(updated).toEqual({ id: 1, nome: 'Henrique' }); + }); + }); + + describe('remove', () => { + it('should remove a user', async () => { + jest.spyOn(repository, 'findOneOrFail').mockResolvedValue({ id: 1 } as any); + jest.spyOn(repository, 'remove').mockResolvedValue({ id: 1 } as any); + const removed = await service.remove(1); + expect(removed.id).toEqual(1); + }); + }); + + describe('enviarCodigoRedefinicao', () => { + it('should send reset code email', async () => { + const user = { email: 'teste@email.com', codigoReset: '', codigoResetExpiracao: new Date() }; + jest.spyOn(repository, 'findOne').mockResolvedValue(user as any); + jest.spyOn(repository, 'save').mockResolvedValue(user as any); + (sendResetEmail as jest.Mock).mockResolvedValue(true); - const expectedUser = { - ...usuario, - foto: 'data:image/png;base64,1', + const result = await service.enviarCodigoRedefinicao('teste@email.com'); + expect(result).toEqual({ message: 'Código enviado para o e-mail' }); + expect(sendResetEmail).toHaveBeenCalledWith('teste@email.com', expect.any(String)); + }); + + it('should throw error if email not provided', async () => { + await expect(service.enviarCodigoRedefinicao('')).rejects.toThrow( + new BadRequestException('Email não forncedio!'), + ); + }); + + it('should throw error if user not found', async () => { + jest.spyOn(repository, 'findOne').mockResolvedValue(null); + await expect(service.enviarCodigoRedefinicao('teste@email.com')).rejects.toThrow( + new NotFoundException('Usuário não encontrado'), + ); + }); + }); + + describe('resetarSenha', () => { + it('should reset password successfully', async () => { + const user = { + email: 'teste@email.com', + codigoReset: '123456', + codigoResetExpiracao: new Date(Date.now() + 3600000), }; + jest.spyOn(repository, 'findOne').mockResolvedValue(user as any); + jest.spyOn(repository, 'save').mockResolvedValue(user as any); - const data = await service.findAllToPublicacao([1]); - expect(data).toEqual([expectedUser]); + const dto: ResetarSenhaDto = { + email: 'teste@email.com', + codigo: '123456', + novaSenha: 'newpassword', + }; + + const result = await service.resetarSenha(dto); + expect(result).toEqual({ message: 'Senha redefinida com sucesso' }); + }); + + it('should throw error if code is invalid or expired', async () => { + const user = { + email: 'teste@email.com', + codigoReset: '123456', + codigoResetExpiracao: new Date(Date.now() - 3600000), // Expirado + }; + jest.spyOn(repository, 'findOne').mockResolvedValue(user as any); + + const dto: ResetarSenhaDto = { + email: 'teste@email.com', + codigo: '654321', + novaSenha: 'newpassword', + }; + + await expect(service.resetarSenha(dto)).rejects.toThrow( + new NotFoundException('Código inválido ou expirado'), + ); + }); + + it('should throw error if user not found', async () => { + jest.spyOn(repository, 'findOne').mockResolvedValue(null); + + const dto: ResetarSenhaDto = { + email: 'naoexiste@email.com', + codigo: '123456', + novaSenha: 'newpassword', + }; + + await expect(service.resetarSenha(dto)).rejects.toThrow( + new NotFoundException('Usuário não encontrado'), + ); + }); + + }); + + describe('allUpdatedUsuariosSince', () => { + it('should get all updated users since timestamp', async () => { + const timestamp = new Date(); + jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ + where: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue([{ id: 1 }]), + } as any); + const users = await service.allUpdatedUsuariosSince(timestamp); + expect(users).toEqual([{ id: 1 }]); + }); + }); + + describe('allCreatedUsuariosSince', () => { + it('should get all created users since timestamp', async () => { + const timestamp = new Date(); + jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ + where: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue([{ id: 1 }]), + } as any); + const users = await service.allCreatedUsuariosSince(timestamp); + expect(users).toEqual([{ id: 1 }]); }); }); });