Pruebas en TypeScript: Unit, Integration, E2E (nivel avanzado)

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Pruebas avanzadas en TypeScript: de Unit a E2E



Las pruebas no son solo una verificación del funcionamiento del código, sino la base del desarrollo profesional en TypeScript. En el nivel avanzado, pasamos de simples asserts a la construcción de pirámides de pruebas aisladas, rápidas y confiables. En este artículo, analizaremos enfoques prácticos para pruebas unitarias, de integración y e2e utilizando las mejores herramientas del ecosistema TypeScript.



1. Pruebas Unitarias Avanzadas con Jest y TypeScript



Las pruebas unitarias verifican módulos aislados. En TypeScript, la complejidad clave radica en trabajar con dependencias, tipos y asincronía.



1.1. Mocks y tipificación con jest.mocked

Utilice jest.mocked para una tipificación completa de los mocks. Esto garantiza que no llamará a un método inexistente.



import { fetchUserData } from './api';import { processUser } from './userProcessor';

jest.mock('./api');

const mockedFetchUserData = jest.mocked(fetchUserData);

describe('processUser', () => { it('debe procesar los datos del usuario', async () => { const mockUser = { id: 1, name: 'Alice', email: 'alice@test.com' }; mockedFetchUserData.mockResolvedValue(mockUser);

const result = await processUser(1);

expect(result).toEqual({ displayName: 'Alice', contact: 'alice@test.com' }); expect(mockedFetchUserData).toHaveBeenCalledWith(1); });

it('debe lanzar un error si falta el email', async () => { mockedFetchUserData.mockResolvedValue({ id: 2, name: 'Bob', email: null }); await expect(processUser(2)).rejects.toThrow('Email is required'); });});


1.2. Pruebas de tipos complejos y genéricos

Para funciones con genéricos, cree tipos auxiliares de prueba para evitar la duplicación.



// Códigofunction getFirstElement<T>(arr: T[]): T | undefined {  return arr[0];}

// Pruebatype TestArray = number[];const array: TestArray = [10, 20, 30];

describe('getFirstElement', () => { it('debe devolver el primer elemento numérico', () => { const result = getFirstElement(array); expect(result).toBe(10); // TypeScript infiere automáticamente el tipo number });

it('debe devolver undefined para un array vacío', () => { const result = getFirstElement([]); expect(result).toBeUndefined(); });});


2. Pruebas de Integración: Base de Datos y API



Las pruebas de integración verifican la interacción de los módulos: controladores, servicios y base de datos. Para aplicaciones TypeScript en Node.js, la combinación ideal es Jest + Supertest + Testcontainers.



2.1. Configuración de la base de datos de prueba con Testcontainers

Testcontainers levanta PostgreSQL en Docker, garantizando un entorno limpio para cada prueba.



import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';import { Client } from 'pg';

let container: StartedPostgreSqlContainer;let client: Client;

beforeAll(async () => { container = await new PostgreSqlContainer().start(); client = new Client({ connectionString: container.getConnectionUri() }); await client.connect(); await client.query(` CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL ); `);}, 30000); // tiempo de espera de 30 segundos para descargar la imagen

afterAll(async () => { await client.end(); await container.stop();});

describe('User Repository', () => { it('debe crear y devolver un usuario', async () => { const res = await client.query( `INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *`, ['Test', 'test@example.com'] ); expect(res.rows[0].name).toBe('Test'); });});


2.2. Pruebas de API REST con Supertest

Iniciamos la aplicación Express y la prueba

Blogs

Book Recommendations