FASE 7 COMPLETADA: Testing y Lanzamiento - PROYECTO FINALIZADO
Some checks failed
CI/CD Pipeline / 🧪 Tests (push) Has been cancelled
CI/CD Pipeline / 🏗️ Build (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Production (push) Has been cancelled
CI/CD Pipeline / 🏷️ Create Release (push) Has been cancelled
CI/CD Pipeline / 🧹 Cleanup (push) Has been cancelled

Implementados 4 módulos con agent swarm:

1. TESTING FUNCIONAL (Jest)
   - Configuración Jest + ts-jest
   - Tests unitarios: auth, booking, court (55 tests)
   - Tests integración: routes (56 tests)
   - Factories y utilidades de testing
   - Coverage configurado (70% servicios)
   - Scripts: test, test:watch, test:coverage

2. TESTING DE USUARIO (Beta)
   - Sistema de beta testers
   - Feedback con categorías y severidad
   - Beta issues tracking
   - 8 testers de prueba creados
   - API completa para gestión de feedback

3. DOCUMENTACIÓN COMPLETA
   - API.md - 150+ endpoints documentados
   - SETUP.md - Guía de instalación
   - DEPLOY.md - Deploy en VPS
   - ARCHITECTURE.md - Arquitectura del sistema
   - APP_STORE.md - Material para stores
   - Postman Collection completa
   - PM2 ecosystem config
   - Nginx config con SSL

4. GO LIVE Y PRODUCCIÓN
   - Sistema de monitoreo (logs, health checks)
   - Servicio de alertas multi-canal
   - Pre-deploy check script
   - Docker + docker-compose producción
   - Backup automatizado
   - CI/CD GitHub Actions
   - Launch checklist completo

ESTADÍSTICAS FINALES:
- Fases completadas: 7/7
- Archivos creados: 250+
- Líneas de código: 60,000+
- Endpoints API: 150+
- Tests: 110+
- Documentación: 5,000+ líneas

PROYECTO COMPLETO Y LISTO PARA PRODUCCIÓN
This commit is contained in:
2026-01-31 22:30:44 +00:00
parent e135e7ad24
commit dd10891432
61 changed files with 19256 additions and 142 deletions

View File

@@ -0,0 +1,304 @@
import request from 'supertest';
import app from '../../../src/app';
import { setupTestDb, teardownTestDb, resetDatabase } from '../../utils/testDb';
import { createUser } from '../../utils/factories';
import { generateTokens } from '../../utils/auth';
describe('Auth Routes Integration Tests', () => {
beforeAll(async () => {
await setupTestDb();
});
afterAll(async () => {
await teardownTestDb();
});
beforeEach(async () => {
await resetDatabase();
});
describe('POST /api/v1/auth/register', () => {
const validRegisterData = {
email: 'test@example.com',
password: 'Password123!',
firstName: 'Test',
lastName: 'User',
phone: '+1234567890',
playerLevel: 'BEGINNER',
handPreference: 'RIGHT',
positionPreference: 'BOTH',
};
it('should register a new user successfully', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/register')
.send(validRegisterData);
// Assert
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('success', true);
expect(response.body.data).toHaveProperty('user');
expect(response.body.data).toHaveProperty('accessToken');
expect(response.body.data).toHaveProperty('refreshToken');
expect(response.body.data.user).toHaveProperty('email', validRegisterData.email);
expect(response.body.data.user).toHaveProperty('firstName', validRegisterData.firstName);
expect(response.body.data.user).not.toHaveProperty('password');
});
it('should return 409 when email already exists', async () => {
// Arrange
await createUser({ email: validRegisterData.email });
// Act
const response = await request(app)
.post('/api/v1/auth/register')
.send(validRegisterData);
// Assert
expect(response.status).toBe(409);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('message', 'El email ya está registrado');
});
it('should return 400 when email is invalid', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/register')
.send({ ...validRegisterData, email: 'invalid-email' });
// Assert
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
});
it('should return 400 when password is too short', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/register')
.send({ ...validRegisterData, password: '123' });
// Assert
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
});
it('should return 400 when required fields are missing', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/register')
.send({ email: 'test@example.com', password: 'Password123!' });
// Assert
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
});
});
describe('POST /api/v1/auth/login', () => {
const validLoginData = {
email: 'login@example.com',
password: 'Password123!',
};
it('should login with valid credentials', async () => {
// Arrange
await createUser({
email: validLoginData.email,
password: validLoginData.password,
firstName: 'Login',
lastName: 'Test',
});
// Act
const response = await request(app)
.post('/api/v1/auth/login')
.send(validLoginData);
// Assert
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('success', true);
expect(response.body.data).toHaveProperty('user');
expect(response.body.data).toHaveProperty('accessToken');
expect(response.body.data).toHaveProperty('refreshToken');
expect(response.body.data.user).toHaveProperty('email', validLoginData.email);
expect(response.body.data.user).not.toHaveProperty('password');
});
it('should return 401 with invalid password', async () => {
// Arrange
await createUser({
email: validLoginData.email,
password: validLoginData.password,
});
// Act
const response = await request(app)
.post('/api/v1/auth/login')
.send({ ...validLoginData, password: 'WrongPassword123!' });
// Assert
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('message', 'Email o contraseña incorrectos');
});
it('should return 401 when user not found', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/login')
.send({ email: 'nonexistent@example.com', password: 'Password123!' });
// Assert
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('message', 'Email o contraseña incorrectos');
});
it('should return 401 when user is inactive', async () => {
// Arrange
await createUser({
email: validLoginData.email,
password: validLoginData.password,
isActive: false,
});
// Act
const response = await request(app)
.post('/api/v1/auth/login')
.send(validLoginData);
// Assert
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('message', 'Usuario desactivado');
});
it('should return 400 with invalid email format', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/login')
.send({ email: 'invalid-email', password: 'Password123!' });
// Assert
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
});
});
describe('GET /api/v1/auth/me', () => {
it('should return user profile when authenticated', async () => {
// Arrange
const user = await createUser({
email: 'profile@example.com',
firstName: 'Profile',
lastName: 'User',
});
const { accessToken } = generateTokens({
userId: user.id,
email: user.email,
role: user.role,
});
// Act
const response = await request(app)
.get('/api/v1/auth/me')
.set('Authorization', `Bearer ${accessToken}`);
// Assert
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('success', true);
expect(response.body.data).toHaveProperty('id', user.id);
expect(response.body.data).toHaveProperty('email', user.email);
expect(response.body.data).toHaveProperty('firstName', 'Profile');
expect(response.body.data).not.toHaveProperty('password');
});
it('should return 401 when no token provided', async () => {
// Act
const response = await request(app)
.get('/api/v1/auth/me');
// Assert
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('message', 'Token de autenticación no proporcionado');
});
it('should return 401 with invalid token', async () => {
// Act
const response = await request(app)
.get('/api/v1/auth/me')
.set('Authorization', 'Bearer invalid-token');
// Assert
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('success', false);
});
});
describe('POST /api/v1/auth/refresh', () => {
it('should refresh access token with valid refresh token', async () => {
// Arrange
const user = await createUser({ email: 'refresh@example.com' });
const { refreshToken } = generateTokens({
userId: user.id,
email: user.email,
role: user.role,
});
// Act
const response = await request(app)
.post('/api/v1/auth/refresh')
.send({ refreshToken });
// Assert
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('success', true);
expect(response.body.data).toHaveProperty('accessToken');
});
it('should return 400 when refresh token is missing', async () => {
// Act
const response = await request(app)
.post('/api/v1/auth/refresh')
.send({});
// Assert
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
});
});
describe('POST /api/v1/auth/logout', () => {
it('should logout successfully', async () => {
// Arrange
const user = await createUser({ email: 'logout@example.com' });
const { accessToken } = generateTokens({
userId: user.id,
email: user.email,
role: user.role,
});
// Act
const response = await request(app)
.post('/api/v1/auth/logout')
.set('Authorization', `Bearer ${accessToken}`);
// Assert
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('success', true);
expect(response.body).toHaveProperty('message', 'Logout exitoso');
});
it('should allow logout without authentication', async () => {
// Act - logout endpoint doesn't require authentication
const response = await request(app)
.post('/api/v1/auth/logout');
// Assert - logout is allowed without auth (just returns success)
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('success', true);
});
});
});