🎓 Initial commit: Math2 Platform - Plataforma de Álgebra Lineal PRO
Some checks failed
Test Suite / test-backend (push) Has been cancelled
Test Suite / test-frontend (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / coverage-check (push) Has been cancelled

 Características:
- 45 ejercicios universitarios (Basic → Advanced)
- Renderizado LaTeX profesional
- IA generativa (Z.ai/DashScope)
- Docker 9 servicios
- Tests 123/123 pasando
- Seguridad enterprise (JWT, XSS, Rate limiting)

🐳 Infraestructura:
- Next.js 14 + Node.js 20
- PostgreSQL 15 + Redis 7
- Docker Compose completo
- Nginx + SSL ready

📚 Documentación:
- 5 informes técnicos completos
- README profesional
- Scripts de deployment automatizados

Estado: Producción lista 
This commit is contained in:
Renato
2026-03-31 11:27:11 -03:00
commit bc43c9e772
309 changed files with 84845 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
/**
* System Config Service Tests
*
* Unit tests for SystemConfigService
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { PrismaClient } from '@prisma/client';
import { SystemConfigService } from '../src/modules/system-config/system-config.service';
const prisma = new PrismaClient();
const service = new SystemConfigService(prisma);
describe('SystemConfigService', () => {
beforeAll(async () => {
// Clean up test configs
await prisma.systemConfig.deleteMany({
where: { key: { startsWith: 'test.' } },
});
});
afterAll(async () => {
// Clean up after tests
await prisma.systemConfig.deleteMany({
where: { key: { startsWith: 'test.' } },
});
await prisma.$disconnect();
});
describe('upsert', () => {
it('should create a new config', async () => {
await service.upsert({
key: 'test.create',
value: 'test-value',
category: 'platform',
dataType: 'string',
});
const value = await service.get('test.create');
expect(value).toBe('test-value');
});
it('should update existing config', async () => {
await service.upsert({
key: 'test.update',
value: 'original',
category: 'platform',
});
await service.upsert({
key: 'test.update',
value: 'updated',
category: 'platform',
});
const value = await service.get('test.update');
expect(value).toBe('updated');
});
it('should track change history', async () => {
await service.upsert({
key: 'test.history',
value: 'v1',
category: 'platform',
}, 'user-1');
await service.upsert({
key: 'test.history',
value: 'v2',
category: 'platform',
}, 'user-2');
const history = await service.getChangeHistory('test.history');
expect(history).toHaveLength(1);
expect(history[0].value).toBe('v1');
expect(history[0].user).toBe('user-1');
});
});
describe('getParsed', () => {
it('should parse boolean values', async () => {
await service.upsert({
key: 'test.bool.true',
value: 'true',
category: 'platform',
dataType: 'boolean',
});
await service.upsert({
key: 'test.bool.false',
value: 'false',
category: 'platform',
dataType: 'boolean',
});
expect(await service.getParsed('test.bool.true')).toBe(true);
expect(await service.getParsed('test.bool.false')).toBe(false);
});
it('should parse number values', async () => {
await service.upsert({
key: 'test.number',
value: '42.5',
category: 'platform',
dataType: 'number',
});
const value = await service.getParsed('test.number');
expect(value).toBe(42.5);
});
it('should parse json values', async () => {
await service.upsert({
key: 'test.json',
value: '{"key": "value", "num": 123}',
category: 'platform',
dataType: 'json',
});
const value = await service.getParsed('test.json');
expect(value).toEqual({ key: 'value', num: 123 });
});
});
describe('getByCategory', () => {
it('should filter by category', async () => {
await service.upsert({
key: 'test.cat.platform',
value: '1',
category: 'platform',
isPublic: true,
});
await service.upsert({
key: 'test.cat.ai',
value: '2',
category: 'ai',
isPublic: true,
});
const platformConfigs = await service.getByCategory('platform');
expect(platformConfigs.some(c => c.key === 'test.cat.platform')).toBe(true);
expect(platformConfigs.some(c => c.key === 'test.cat.ai')).toBe(false);
});
it('should filter public/private configs', async () => {
await service.upsert({
key: 'test.public',
value: 'public',
category: 'platform',
isPublic: true,
});
await service.upsert({
key: 'test.private',
value: 'private',
category: 'platform',
isPublic: false,
});
const publicConfigs = await service.getByCategory('platform');
expect(publicConfigs.some(c => c.key === 'test.public')).toBe(true);
expect(publicConfigs.some(c => c.key === 'test.private')).toBe(false);
const allConfigs = await service.getByCategory('platform', true);
expect(allConfigs.some(c => c.key === 'test.private')).toBe(true);
});
});
describe('getPublicConfigs', () => {
it('should return only public configs', async () => {
await service.upsert({
key: 'test.public.all',
value: 'visible',
category: 'platform',
isPublic: true,
});
await service.upsert({
key: 'test.private.all',
value: 'hidden',
category: 'platform',
isPublic: false,
});
const configs = await service.getPublicConfigs();
expect(configs.some(c => c.key === 'test.public.all')).toBe(true);
expect(configs.some(c => c.key === 'test.private.all')).toBe(false);
});
});
describe('updateValue', () => {
it('should update only the value', async () => {
await service.upsert({
key: 'test.update.value',
value: 'original',
description: 'Original description',
category: 'platform',
});
await service.updateValue('test.update.value', 'new-value', 'admin-1');
const config = await prisma.systemConfig.findUnique({
where: { key: 'test.update.value' },
});
expect(config?.value).toBe('new-value');
expect(config?.description).toBe('Original description');
expect(config?.category).toBe('platform');
});
it('should throw error for non-existent key', async () => {
await expect(
service.updateValue('test.nonexistent', 'value')
).rejects.toThrow("Config with key 'test.nonexistent' not found");
});
});
describe('delete', () => {
it('should delete config', async () => {
await service.upsert({
key: 'test.delete',
value: 'to-delete',
category: 'platform',
});
await service.delete('test.delete');
const value = await service.get('test.delete');
expect(value).toBeNull();
});
});
describe('parseValue', () => {
it('should parse different data types correctly', () => {
expect(service.parseValue('123', 'number')).toBe(123);
expect(service.parseValue('45.67', 'number')).toBe(45.67);
expect(service.parseValue('true', 'boolean')).toBe(true);
expect(service.parseValue('1', 'boolean')).toBe(true);
expect(service.parseValue('false', 'boolean')).toBe(false);
expect(service.parseValue('{"a":1}', 'json')).toEqual({ a: 1 });
expect(service.parseValue('2024-01-01', 'date')).toEqual(new Date('2024-01-01'));
expect(service.parseValue('plain string', 'string')).toBe('plain string');
});
it('should handle invalid json gracefully', () => {
expect(service.parseValue('invalid json', 'json')).toBe('invalid json');
});
});
});