From 28ab733beef9a6e49d13506f11a082e83596c0af Mon Sep 17 00:00:00 2001 From: tyrannusss Date: Tue, 21 Oct 2025 17:14:17 -0600 Subject: [PATCH] creacion de .spec en usuario y controller --- src/caso-especial/caso-especial.service.ts | 2 +- src/usuario/dto/create-usuario.dto.ts | 35 +++- src/usuario/dto/update-usuario.dto.ts | 14 +- src/usuario/usuario.controller.spec.ts | 191 +++++++++++++++++++++ src/usuario/usuario.controller.ts | 55 +++++- 5 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 src/usuario/usuario.controller.spec.ts diff --git a/src/caso-especial/caso-especial.service.ts b/src/caso-especial/caso-especial.service.ts index b033ccf..40b9232 100644 --- a/src/caso-especial/caso-especial.service.ts +++ b/src/caso-especial/caso-especial.service.ts @@ -189,7 +189,7 @@ export class CasoEspecialService { text: correo.msj, html: '', - fecha_recibido: '', + fecha_recibido: new Date(), }; // Envía correo diff --git a/src/usuario/dto/create-usuario.dto.ts b/src/usuario/dto/create-usuario.dto.ts index d7960fe..c5d1276 100644 --- a/src/usuario/dto/create-usuario.dto.ts +++ b/src/usuario/dto/create-usuario.dto.ts @@ -1 +1,34 @@ -export class CreateUsuarioDto {} +import { + IsString, + IsBoolean, + IsNumber, + IsEmail, + IsOptional, + MinLength, + MaxLength, +} from 'class-validator'; + +export class CreateUsuarioDto { + @IsEmail() + @IsString() + @MaxLength(100) + usuario: string; + + @IsOptional() + @IsString() + @MinLength(6) + @MaxLength(60) + password?: string; + + @IsOptional() + @IsString() + @MaxLength(70) + nombre?: string; + + @IsOptional() + @IsBoolean() + activo?: boolean; + + @IsNumber() + tipoUsuario: number; +} diff --git a/src/usuario/dto/update-usuario.dto.ts b/src/usuario/dto/update-usuario.dto.ts index a2b8fbc..e06b592 100644 --- a/src/usuario/dto/update-usuario.dto.ts +++ b/src/usuario/dto/update-usuario.dto.ts @@ -1,4 +1,16 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateUsuarioDto } from './create-usuario.dto'; +import { IsString, IsEmail, IsOptional, MaxLength } from 'class-validator'; -export class UpdateUsuarioDto extends PartialType(CreateUsuarioDto) {} +export class UpdateUsuarioDto { + @IsOptional() + @IsEmail() + @IsString() + @MaxLength(100) + correo?: string; + + @IsOptional() + @IsString() + @MaxLength(70) + nombre?: string; +} diff --git a/src/usuario/usuario.controller.spec.ts b/src/usuario/usuario.controller.spec.ts new file mode 100644 index 0000000..08b80c1 --- /dev/null +++ b/src/usuario/usuario.controller.spec.ts @@ -0,0 +1,191 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsuarioController } from './usuario.controller'; +import { UsuarioService } from './usuario.service'; +import { AuthGuard } from '@nestjs/passport'; +import { UpdateUsuarioDto } from './dto/update-usuario.dto'; +import { + BadRequestException, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; + +// Mocks +const mockUsuarioService = { + escolares: jest.fn(), + newPasswordAlumno: jest.fn(), + newPasswordResponsable: jest.fn(), + findResponsable: jest.fn(), + findResponsables: jest.fn(), + actualizarResponsable: jest.fn(), +}; + +const mockAuthGuard = { + canActivate: jest.fn(() => true), +}; + +describe('UsuarioController', () => { + let controller: UsuarioController; + let service: UsuarioService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [UsuarioController], + providers: [ + { + provide: UsuarioService, + useValue: mockUsuarioService, + }, + ], + }) + .overrideGuard(AuthGuard('jwt')) + .useValue(mockAuthGuard) + .compile(); + + controller = module.get(UsuarioController); + service = module.get(UsuarioService); + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); + + describe('escolares', () => { + it('should call escolares service with correct parameter', async () => { + const numeroDeCuenta = '12345678'; + const expectedResult = { + nombre: 'Juan Perez', + creditos: 80, + carrera: 'LIC. EN DERECHO', + }; + + mockUsuarioService.escolares.mockResolvedValue(expectedResult); + + const result = await controller.escolares(numeroDeCuenta); + + expect(service.escolares).toHaveBeenCalledWith(numeroDeCuenta); + expect(result).toEqual(expectedResult); + }); + }); + + describe('newPasswordAlumno', () => { + it('should call newPasswordAlumno service with correct parameter', async () => { + const idServicio = 1; + const expectedResult = { + message: 'Se envió un correo con una contraseña nueva al alumno.', + }; + + mockUsuarioService.newPasswordAlumno.mockResolvedValue(expectedResult); + + const result = await controller.newPasswordAlumno(idServicio); + + expect(service.newPasswordAlumno).toHaveBeenCalledWith(idServicio); + expect(result).toEqual(expectedResult); + }); + }); + + describe('newPasswordResponsable', () => { + it('should call newPasswordResponsable service with correct parameter', async () => { + const idUsuario = 1; + const expectedResult = { + message: 'Se envió un correo con una contraseña nueva al responsable.', + }; + + mockUsuarioService.newPasswordResponsable.mockResolvedValue( + expectedResult, + ); + + const result = await controller.newPasswordResponsable(idUsuario); + + expect(service.newPasswordResponsable).toHaveBeenCalledWith(idUsuario); + expect(result).toEqual(expectedResult); + }); + }); + + describe('findResponsable', () => { + it('should call findResponsable service with correct parameter', async () => { + const idUsuario = 1; + const expectedResult = { + idUsuario: 1, + usuario: 'responsable@unam.mx', + nombre: 'Responsable Test', + activo: true, + }; + + mockUsuarioService.findResponsable.mockResolvedValue(expectedResult); + + const result = await controller.findResponsable(idUsuario); + + expect(service.findResponsable).toHaveBeenCalledWith(idUsuario); + expect(result).toEqual(expectedResult); + }); + + it('should handle when responsable is not found', async () => { + const idUsuario = 999; + const error = new NotFoundException('Responsable no encontrado'); + + mockUsuarioService.findResponsable.mockRejectedValue(error); + + await expect(controller.findResponsable(idUsuario)).rejects.toThrow( + NotFoundException, + ); + }); + }); + + describe('findResponsables', () => { + it('should call findResponsables service with default parameters', async () => { + const expectedResult = { + count: 2, + responsables: [ + { + idUsuario: 1, + usuario: 'resp1@unam.mx', + nombre: 'Resp 1', + activo: true, + }, + { + idUsuario: 2, + usuario: 'resp2@unam.mx', + nombre: 'Resp 2', + activo: true, + }, + ], + }; + + mockUsuarioService.findResponsables.mockResolvedValue(expectedResult); + + const result = await controller.findResponsables(); + + expect(service.findResponsables).toHaveBeenCalledWith(1, '', ''); + expect(result).toEqual(expectedResult); + }); + + it('should call findResponsables service with custom parameters', async () => { + const pagina = 2; + const nombre = 'Juan'; + const correo = 'juan@unam.mx'; + const expectedResult = { + count: 1, + responsables: [ + { + idUsuario: 1, + usuario: 'juan@unam.mx', + nombre: 'Juan Perez', + activo: true, + }, + ], + }; + + mockUsuarioService.findResponsables.mockResolvedValue(expectedResult); + + const result = await controller.findResponsables(pagina, nombre, correo); + + expect(service.findResponsables).toHaveBeenCalledWith( + pagina, + nombre, + correo, + ); + expect(result).toEqual(expectedResult); + }); + }); +}); diff --git a/src/usuario/usuario.controller.ts b/src/usuario/usuario.controller.ts index dc4327c..d808646 100644 --- a/src/usuario/usuario.controller.ts +++ b/src/usuario/usuario.controller.ts @@ -5,13 +5,66 @@ import { Body, Patch, Param, - Delete, + Query, + ParseIntPipe, + UseGuards, } from '@nestjs/common'; import { UsuarioService } from './usuario.service'; import { CreateUsuarioDto } from './dto/create-usuario.dto'; +import { AuthGuard } from '@nestjs/passport'; import { UpdateUsuarioDto } from './dto/update-usuario.dto'; @Controller('usuario') export class UsuarioController { constructor(private readonly usuarioService: UsuarioService) {} + + @Post('escolares/:numeroDeCuenta') + async escolares(@Param('numeroDeCuenta') numeroDeCuenta: string) { + return await this.usuarioService.escolares(numeroDeCuenta); + } + + @Post('new-password-alumno/:idServicio') + @UseGuards(AuthGuard('jwt')) + async newPasswordAlumno( + @Param('idServicio', ParseIntPipe) idServicio: number, + ) { + return await this.usuarioService.newPasswordAlumno(idServicio); + } + + @Post('new-password-responsable/:idUsuario') + @UseGuards(AuthGuard('jwt')) + async newPasswordResponsable( + @Param('idUsuario', ParseIntPipe) idUsuario: number, + ) { + return await this.usuarioService.newPasswordResponsable(idUsuario); + } + + @Get('responsable/:idUsuario') + @UseGuards(AuthGuard('jwt')) + async findResponsable(@Param('idUsuario', ParseIntPipe) idUsuario: number) { + return await this.usuarioService.findResponsable(idUsuario); + } + + @Get('responsables') + @UseGuards(AuthGuard('jwt')) + async findResponsables( + @Query('pagina', new ParseIntPipe({ optional: true })) pagina: number = 1, + @Query('nombre') nombre: string = '', + @Query('correo') correo: string = '', + ) { + return await this.usuarioService.findResponsables(pagina, nombre, correo); + } + + @Patch('responsable/:idUsuario') + @UseGuards(AuthGuard('jwt')) + async actualizarResponsable( + @Param('idUsuario', ParseIntPipe) idUsuario: number, + @Body() updateUsuarioDto: UpdateUsuarioDto, + ) { + return await this.usuarioService.actualizarResponsable( + idUsuario, + updateUsuarioDto.correo, + updateUsuarioDto.nombre, + ); + } }