Introducción: ¿Por qué probar código TypeScript?
TypeScript es un superconjunto de JavaScript que añade tipado estático. Sin embargo, los tipos no garantizan una lógica correcta de la aplicación. Las pruebas en TypeScript no son solo una "buena práctica", sino una necesidad para mantener la calidad del código, prevenir regresiones y acelerar el desarrollo.
En este artículo, analizaremos tres niveles principales de pruebas: unit (pruebas unitarias), integration (pruebas de integración) y e2e (end-to-end). Aprenderás qué herramientas usar, verás ejemplos de código y entenderás cómo construir una estrategia de pruebas equilibrada para tu proyecto TypeScript.
1. Pruebas Unitarias en TypeScript
¿Qué son las pruebas unitarias?
Las pruebas unitarias verifican módulos o funciones aisladas. Se ejecutan rápidamente y no requieren dependencias externas (bases de datos, red, sistema de archivos). El objetivo principal es asegurarse de que cada pequeña unidad de código funcione correctamente.
Herramientas: Jest + ts-jest
El framework más popular para pruebas unitarias en TypeScript es Jest con el transpilador ts-jest. Soporta mocks, espías, cobertura y se integra excelentemente con TypeScript.
Ejemplo de prueba unitaria
Supongamos que tenemos una función para calcular un descuento:
// discount.tsexport function calculateDiscount(price: number, discountPercent: number): number { if (price < 0 || discountPercent < 0 || discountPercent > 100) { throw new Error('Invalid input'); } return price * (1 - discountPercent / 100);}Escribimos la prueba:
// discount.test.tsimport { calculateDiscount } from './discount';
describe('calculateDiscount', () => { it('should apply 10% discount correctly', () => { expect(calculateDiscount(1000, 10)).toBe(900); });
it('should throw error for negative price', () => { expect(() => calculateDiscount(-100, 10)).toThrow('Invalid input'); });
it('should handle 0% discount', () => { expect(calculateDiscount(500, 0)).toBe(500); });});Ejecución: npx jest. Jest encontrará automáticamente todos los archivos *.test.ts.
Mejores prácticas para pruebas unitarias
- Aísla las dependencias — usa mocks (jest.mock) para módulos que acceden a la BD o API.
- Prueba casos límite — arrays vacíos, null, números negativos.
- Sigue el principio FIRST — Fast, Isolated, Repeatable, Self-validating, Timely.
- Usa describe/it — para una estructura de pruebas legible.
2. Pruebas de Integración (Integration Tests)
¿Qué verifican las pruebas de integración?
Las pruebas de integración verifican la interacción de varios módulos: controlador + servicio + base de datos, o endpoint API + middleware. Son más lentas que las pruebas unitarias, pero brindan mayor confianza en el correcto acoplamiento de los componentes.
Herramientas: Supertest + Jest + BD en memoria
Para probar APIs Express/Node.js a menudo se usa Supertest (afirmaciones HTTP) junto con Jest. La base de datos se puede levantar en memoria (por ejemplo, mongodb-memory-server o sqlite3).
Ejemplo de prueba de integración para una API Express
Supongamos que tenemos una API REST simple para gestionar usuarios:
// app.tsimport express from 'express';import { userRouter } from './routes/userRoutes';
const app = express();app.use(express.json());app.use('/api/users', userRouter);
export { app };Prueba con Supertest:
// user.integration.test.tsimport request from 'supertest';import { app } from '../app';
describe('POST /api/users', () => { it('should create a new user and return 201', async () => {
```