Creacion de caso-especial.controller.spec.ts

This commit is contained in:
2025-10-15 17:12:44 -06:00
parent cdf3b761e4
commit 120e838e63
7 changed files with 354 additions and 82 deletions
+131 -5
View File
@@ -28,13 +28,14 @@
"moment": "^2.30.1",
"multer": "^2.0.2",
"mysql": "^2.18.1",
"mysql2": "^3.15.2",
"node-domexception": "^2.0.2",
"nodemailer": "^7.0.6",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"typeorm": "^0.3.26"
"typeorm": "^0.3.27"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
@@ -5209,6 +5210,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
@@ -6337,6 +6347,15 @@
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -7533,6 +7552,15 @@
"node": ">=18"
}
},
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"license": "MIT",
"dependencies": {
"is-property": "^1.0.2"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -8199,6 +8227,12 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
"license": "MIT"
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -9487,6 +9521,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/long": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
"license": "Apache-2.0"
},
"node_modules/lowercase-keys": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
@@ -9510,6 +9550,21 @@
"yallist": "^3.0.2"
}
},
"node_modules/lru.min": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
"integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
@@ -9881,6 +9936,72 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/mysql2": {
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.2.tgz",
"integrity": "sha512-kFm5+jbwR5mC+lo+3Cy46eHiykWSpUtTLOH3GE+AR7GeLq8PgfJcvpMiyVWk9/O53DjQsqm6a3VOOfq7gYWFRg==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
"generate-function": "^2.3.1",
"iconv-lite": "^0.7.0",
"long": "^5.2.1",
"lru.min": "^1.0.0",
"named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.2"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/mysql2/node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/mysql2/node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/named-placeholders": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
"license": "MIT",
"dependencies": {
"lru-cache": "^7.14.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/named-placeholders/node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/napi-postinstall": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz",
@@ -11081,6 +11202,11 @@
"node": ">= 18"
}
},
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
},
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
@@ -12315,9 +12441,9 @@
"license": "MIT"
},
"node_modules/typeorm": {
"version": "0.3.26",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.26.tgz",
"integrity": "sha512-o2RrBNn3lczx1qv4j+JliVMmtkPSqEGpG0UuZkt9tCfWkoXKu8MZnjvp2GjWPll1SehwemQw6xrbVRhmOglj8Q==",
"version": "0.3.27",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.27.tgz",
"integrity": "sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A==",
"license": "MIT",
"dependencies": {
"@sqltools/formatter": "^1.2.5",
@@ -12329,7 +12455,7 @@
"dedent": "^1.6.0",
"dotenv": "^16.4.7",
"glob": "^10.4.5",
"sha.js": "^2.4.11",
"sha.js": "^2.4.12",
"sql-highlight": "^6.0.0",
"tslib": "^2.8.1",
"uuid": "^11.1.0",
+6 -2
View File
@@ -39,13 +39,14 @@
"moment": "^2.30.1",
"multer": "^2.0.2",
"mysql": "^2.18.1",
"mysql2": "^3.15.2",
"node-domexception": "^2.0.2",
"nodemailer": "^7.0.6",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"typeorm": "^0.3.26"
"typeorm": "^0.3.27"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
@@ -90,6 +91,9 @@
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
"testEnvironment": "node",
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/$1"
}
}
}
+9 -1
View File
@@ -1,4 +1,12 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { CarreraService } from './carrera.service';
import { CreateCarreraDto } from './dto/create-carrera.dto';
import { UpdateCarreraDto } from './dto/update-carrera.dto';
@@ -0,0 +1,121 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CasoEspecialController } from './caso-especial.controller';
import { CasoEspecialService } from './caso-especial.service';
import { CreateCasoEspecialDto } from './dto/create-caso-especial.dto';
import { UpdateCasoEspecialDto } from './dto/update-caso-especial.dto';
import { FilterCasoEspecialDto } from './dto/filter-caso-especial.dto';
describe('CasoEspecialController', () => {
let controller: CasoEspecialController;
let service: CasoEspecialService;
const mockService = {
create: jest.fn(),
findAllFiltered: jest.fn(),
admin: jest.fn(),
liberarCasoEspecial: jest.fn(),
updateCasoEspecial: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [CasoEspecialController],
providers: [
{
provide: CasoEspecialService,
useValue: mockService,
},
],
}).compile();
controller = module.get<CasoEspecialController>(CasoEspecialController);
service = module.get<CasoEspecialService>(CasoEspecialService);
});
it('debería estar definido', () => {
expect(controller).toBeDefined();
});
it('debería subir un archivo y crear un caso especial', async () => {
const dto: CreateCasoEspecialDto = {
idUsuario: 1,
idCarrera: 2,
idStatus: 1,
numeroCuenta: '123456789',
correo: 'alumno@pcpuma.com',
creditos: '10',
telefono: '5555555555',
fechaInicio: new Date().toISOString(), // formato ISO para IsDateString
fechaFin: new Date(
new Date().setMonth(new Date().getMonth() + 1),
).toISOString(),
fechaNacimiento: '2000-01-01T00:00:00.000Z',
direccion: 'Direccion',
institucion: 'Instituton',
dependencia: 'Dependencia',
motivo: '1',
};
const file = { filename: 'test-file.pdf' } as Express.Multer.File;
const result = { id: 1, ...dto, archivo: file.filename };
mockService.create.mockResolvedValue(result);
const response = await controller.subirArchivo(file, dto);
expect(response.statusCode).toBe(201);
expect(response.data).toEqual(result);
expect(mockService.create).toHaveBeenCalledWith(dto, file.filename);
});
it('debería obtener servicios especiales filtrados', async () => {
const dto: FilterCasoEspecialDto = {
pagina: 1,
idStatus: 2,
nombre: 'alumnonombre',
numeroCuenta: '123456789',
};
const result = [{ id: 1, alumno: '123456' }];
mockService.findAllFiltered.mockResolvedValue(result);
const response = await controller.getServiciosEspeciales(dto);
expect(response.statusCode).toBe(200);
expect(response.data).toEqual(result);
});
it('debería obtener un caso especial por ID', async () => {
const id = 1;
const result = { id, alumno: '123456789' };
mockService.admin.mockResolvedValue(result);
const response = await controller.getCasosEspeciales(id);
expect(response.statusCode).toBe(200);
expect(response.data).toEqual(result);
});
it('debería liberar un caso especial', async () => {
const id = 1;
const result = { id, liberado: true };
mockService.liberarCasoEspecial.mockResolvedValue(result);
const response = await controller.liberacion(id);
expect(response.statusCode).toBe(200);
expect(response.data).toEqual(result);
});
it('debería actualizar un caso especial', async () => {
const id = 1;
const dto: UpdateCasoEspecialDto = { motivo: 1 };
const result = { id, ...dto };
mockService.updateCasoEspecial.mockResolvedValue(result);
const response = await controller.update(dto, id);
expect(response.statusCode).toBe(200);
expect(response.data).toEqual(result);
});
});
@@ -1,73 +1,72 @@
import {
IsEmail,
IsNotEmpty,
IsNumberString,
IsOptional,
IsString,
Length,
IsDateString,
IsNumber,
IsIn,
IsInt,
Matches,
} from 'class-validator';
export class CreateCasoEspecialDto {
@IsNumber()
idUsuario: number;
@IsNumber()
@IsInt()
idCarrera: number;
@IsNumber()
@Length(1, 11)
idStatus: number;
@IsString()
@Length(9, 9)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
numeroCuenta: string;
@IsEmail()
correo: string;
@IsString()
@Length(1, 3)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
creditos : string;
@IsString()
@Length(1, 15)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
telefono: string;
@IsDateString()
fechaInicio: Date;
@IsDateString()
fechaFin: Date;
@IsDateString()
fechaNacimiento: Date;
@IsString()
@Length(1, 200)
direccion: string;
@IsOptional()
@IsString()
@Length(1, 200)
institucion?: string;
@IsOptional()
@IsString()
@Length(1, 200)
dependencia?: string;
@IsOptional()
@IsNumber()
@Length(1, 1)
motivo?: string;
}
IsEmail,
IsNotEmpty,
IsNumberString,
IsOptional,
IsString,
Length,
IsDateString,
IsNumber,
IsIn,
IsInt,
Matches,
} from 'class-validator';
export class CreateCasoEspecialDto {
@IsNumber()
idUsuario: number;
@IsNumber()
@IsInt()
idCarrera: number;
@IsNumber()
@Length(1, 11)
idStatus: number;
@IsString()
@Length(9, 9)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
numeroCuenta: string;
@IsEmail()
correo: string;
@IsString()
@Length(1, 3)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
creditos: string;
@IsString()
@Length(1, 15)
@Matches(/^\d+$/, { message: 'solo puede contener números' })
telefono: string;
@IsDateString()
fechaInicio: String;
@IsDateString()
fechaFin: String;
@IsDateString()
fechaNacimiento: String;
@IsString()
@Length(1, 200)
direccion: string;
@IsOptional()
@IsString()
@Length(1, 200)
institucion?: string;
@IsOptional()
@IsString()
@Length(1, 200)
dependencia?: string;
@IsOptional()
@IsNumber()
@Length(1, 1)
motivo?: string;
}
+13 -2
View File
@@ -1,4 +1,12 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { ServicioService } from './servicio.service';
import { CreateServicioDto } from './dto/create-servicio.dto';
import { UpdateServicioDto } from './dto/update-servicio.dto';
@@ -23,7 +31,10 @@ export class ServicioController {
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateServicioDto: UpdateServicioDto) {
update(
@Param('id') id: string,
@Body() updateServicioDto: UpdateServicioDto,
) {
return this.servicioService.update(+id, updateServicioDto);
}
+3
View File
@@ -10,6 +10,9 @@
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"paths": {
"src/*": ["src/*"]
},
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true,