Saltar al contenidoPedro Farbo
Lección 18 / 2550 min

Pruebas de Integración

Pruebas de Integración

Pruebas que verifican la API completa con base de datos real.

Instalación

bash
npm install -D supertest @types/supertest

Configuración de Test

typescript
// src/test/setup.tsimport { prisma } from '../config/database'; beforeAll(async () => {  // Conectar a la BD de pruebas  await prisma.$connect();}); afterAll(async () => {  await prisma.$disconnect();}); beforeEach(async () => {  // Limpiar tablas antes de cada prueba  await prisma.orderItem.deleteMany();  await prisma.order.deleteMany();  await prisma.review.deleteMany();  await prisma.product.deleteMany();  await prisma.category.deleteMany();  await prisma.user.deleteMany();});

Jest Config para Integración

javascript
// jest.integration.config.jsmodule.exports = {  preset: 'ts-jest',  testEnvironment: 'node',  roots: ['<rootDir>/src'],  testMatch: ['**/*.integration.spec.ts'],  setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'],  testTimeout: 30000,};

Variables de Entorno

env
# .env.testDATABASE_URL="postgresql://postgres:postgres@localhost:5432/ecommerce_test"JWT_SECRET="test-secret"

Helpers de Prueba

typescript
// src/test/helpers.tsimport { prisma } from '../config/database';import bcrypt from 'bcryptjs';import jwt from 'jsonwebtoken'; export const createTestUser = async (data: Partial<User> = {}) => {  return prisma.user.create({    data: {      name: 'Test User',      email: `test-${Date.now()}@email.com`,      password: await bcrypt.hash('123456', 10),      role: 'USER',      ...data,    },  });}; export const createTestCategory = async () => {  return prisma.category.create({    data: {      name: `Category ${Date.now()}`,      slug: `category-${Date.now()}`,    },  });}; export const getAuthToken = (userId: string) => {  return jwt.sign({ sub: userId }, process.env.JWT_SECRET!, {    expiresIn: '1h',  });};

Prueba de Integración

typescript
// src/routes/__tests__/products.integration.spec.tsimport request from 'supertest';import { app } from '../../app';import { createTestUser, createTestCategory, getAuthToken } from '../../test/helpers';import { prisma } from '../../config/database'; describe('Products API', () => {  describe('GET /api/products', () => {    it('debe retornar lista de productos', async () => {      const category = await createTestCategory();      await prisma.product.createMany({        data: [          { name: 'Product 1', slug: 'product-1', price: 100, categoryId: category.id },          { name: 'Product 2', slug: 'product-2', price: 200, categoryId: category.id },        ],      });       const response = await request(app)        .get('/api/products')        .expect(200);       expect(response.body.data).toHaveLength(2);      expect(response.body.pagination).toBeDefined();    });     it('debe filtrar por búsqueda', async () => {      const category = await createTestCategory();      await prisma.product.createMany({        data: [          { name: 'iPhone 15', slug: 'iphone-15', price: 999, categoryId: category.id },          { name: 'MacBook Pro', slug: 'macbook-pro', price: 1999, categoryId: category.id },        ],      });       const response = await request(app)        .get('/api/products?search=iphone')        .expect(200);       expect(response.body.data).toHaveLength(1);      expect(response.body.data[0].name).toBe('iPhone 15');    });  });   describe('POST /api/products', () => {    it('debe crear producto (admin)', async () => {      const admin = await createTestUser({ role: 'ADMIN' });      const category = await createTestCategory();      const token = getAuthToken(admin.id);       const response = await request(app)        .post('/api/products')        .set('Authorization', `Bearer ${token}`)        .send({          name: 'Nuevo Producto',          price: 299.99,          categoryId: category.id,        })        .expect(201);       expect(response.body.name).toBe('Nuevo Producto');      expect(response.body.slug).toBe('nuevo-producto');    });     it('debe rechazar sin autenticación', async () => {      await request(app)        .post('/api/products')        .send({ name: 'Test', price: 100 })        .expect(401);    });     it('debe rechazar usuarios no admin', async () => {      const user = await createTestUser({ role: 'USER' });      const token = getAuthToken(user.id);       await request(app)        .post('/api/products')        .set('Authorization', `Bearer ${token}`)        .send({ name: 'Test', price: 100 })        .expect(403);    });  });});

Scripts

json
{  "scripts": {    "test:integration": "dotenv -e .env.test -- jest --config jest.integration.config.js --runInBand"  }}

Resumen

  • ✅ Supertest para HTTP requests
  • ✅ Base de datos de prueba aislada
  • ✅ Helpers reutilizables
  • ✅ Pruebas de autenticación/autorización

Próxima clase: Documentación con Swagger! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e