msw para TypeScript: guía completa con ejemplos prácticos

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

msw para TypeScript: guía completa con ejemplos prácticos

¿Qué es msw y para qué sirve?

Mock Service Worker (msw) es una biblioteca para interceptar y simular peticiones de red a nivel de Service Worker API. A diferencia de soluciones tradicionales (como axios-mock-adapter o nock), msw opera a nivel del navegador o Node.js, interceptando peticiones HTTP reales y devolviendo respuestas predefinidas. Esto permite probar aplicaciones sin necesidad de ejecutar un servidor real ni modificar el código de la aplicación.

El objetivo principal de msw es ofrecer una herramienta unificada para simular APIs tanto en pruebas de navegador (usando un Service Worker real) como en pruebas de servidor (Node.js). La biblioteca es especialmente útil para desarrolladores que usan TypeScript, ya que proporciona tipado estricto para todas las peticiones y respuestas. msw es ideal para pruebas unitarias, pruebas de integración y para desarrollar frontend de forma aislada del backend.

La gran ventaja de msw es que los mocks funcionan a nivel de red, no a nivel de código. Esto significa que cualquier biblioteca para hacer peticiones HTTP (fetch, axios, graphql-request, etc.) será interceptada automáticamente sin configuración adicional. La biblioteca soporta REST API, GraphQL y también permite manejar conexiones WebSocket (mediante extensiones).

Instalación

Para instalar msw en un proyecto TypeScript, ejecuta uno de los siguientes comandos:

# npm
npm install msw --save-dev

# yarn
yarn add msw --dev

# pnpm
pnpm add msw --save-dev

Después de la instalación, debes inicializar el Service Worker para uso en el navegador:

npx msw init public/ --save

Para uso en servidor (Node.js) no se requiere inicialización adicional.

Inicio rápido — ejemplo mínimo funcional

Vamos a crear un mock simple para una REST API. El ejemplo incluye la definición de un manejador, la configuración del servidor y una petición de prueba.

// handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('https://api.example.com/user', () => {
    return HttpResponse.json({
      id: 'c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3f',
      firstName: 'Juan',
      lastName: 'Pérez',
    });
  }),
];

// server.ts (para Node.js)
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);

// test.ts
import { server } from './server';

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('debería obtener el usuario', async () => {
  const response = await fetch('https://api.example.com/user');
  const data = await response.json();
  expect(data.firstName).toBe('Juan');
});

Métodos y funciones principales

1. http.get()

Firma: http.get(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Descripción: Crea un manejador para peticiones GET en la URL especificada. Soporta cadenas exactas, expresiones regulares y patrones con parámetros.

import { http, HttpResponse } from 'msw';

export const handler = http.get('https://api.example.com/users/:id', ({ params }) => {
  const { id } = params;
  return HttpResponse.json({ id, name: 'Usuario ' + id });
});

2. http.post()

Firma: http.post(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Descripción: Crea un manejador para peticiones POST. Permite leer el cuerpo de la petición usando request.json().

import { http, HttpResponse } from 'msw';

export const handler = http.post('https://api.example.com/users', async ({ request }) => {
  const body = await request.json();
  return HttpResponse.json({ message: 'Usuario creado', data: body }, { status: 201 });
});

3. http.put()

Firma: http.put(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Descripción: Crea un manejador para peticiones PUT. Similar a POST, permite leer el cuerpo de la petición.

import { http, HttpResponse } from 'msw';

export const handler = http.put('https://api.example.com/users/:id', async ({ params, request }) => {
  const { id } = params;
  const body = await request.json();
  return HttpResponse.json({ id, ...body });
});

4. http.delete()

Firma: http.delete(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Descripción: Crea un manejador para peticiones DELETE. Útil para simular la eliminación de recursos.

import { http, HttpResponse } from 'msw';

export const handler = http.delete('https://api.example.com/users/:id', ({ params }) => {
  const { id } = params;
  return HttpResponse.json({ message: `Usuario ${id} eliminado` });
});

5. http.all()

Firma: http.all(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Descripción: Crea un manejador que responde a cualquier método HTTP (GET, POST, PUT, DELETE, etc.) en la URL especificada.

import { http, HttpResponse } from 'msw';

export const handler = http.all('https://api.example.com/*', () => {
  return HttpResponse.json({ message: 'Interceptado por msw' });
});

6. HttpResponse.json()

Firma: HttpResponse.json(body: any, init?: ResponseInit)

Descripción: Crea una respuesta HTTP con contenido JSON. Acepta un objeto como cuerpo y opciones adicionales (status, headers, etc.).

import { HttpResponse } from 'msw';

const response = HttpResponse.json(
  { success: true, data: [] },
  { status: 200, headers: { 'X-Custom-Header': 'valor' } }
);

7. HttpResponse.text()

Firma: HttpResponse.text(body: string, init?: ResponseInit)

Descripción: Crea una respuesta HTTP con contenido de texto plano.

import { HttpResponse } from 'msw';

const response = HttpResponse.text('Hola mundo', { status: 200 });

8. HttpResponse.xml()

Firma: HttpResponse.xml(body: string, init?: ResponseInit)

Descripción: Crea una respuesta HTTP con contenido XML. Útil para simular APIs que devuelven XML.

import { HttpResponse } from 'msw';

const xmlContent = 'valor';
const response = HttpResponse.xml(xmlContent, { status: 200 });

9. HttpResponse.arrayBuffer()

Firma: HttpResponse.arrayBuffer(body: ArrayBuffer, init?: ResponseInit)

Descripción: Crea una respuesta HTTP con un ArrayBuffer. Ideal para simular la descarga de archivos binarios.

import { HttpResponse } from 'msw';

const buffer = new ArrayBuffer(8);
const response = HttpResponse.arrayBuffer(buffer, {
  headers: { 'Content-Type': 'application/octet-stream' }
});

10. delay()

Firma: delay(ms: number)

Descripción: Función para simular latencia de red. Se usa dentro del manejador para retrasar la respuesta.

import { http, HttpResponse, delay } from 'msw';

export const handler = http.get('https://api.example.com/slow', async () => {
  await delay(2000); // Simula 2 segundos de latencia
  return HttpResponse.json({ message: 'Respuesta retardada' });
});

11. bypass()

Firma: bypass(req: Request): Promise

Descripción: Permite pasar una petición directamente al servidor real, sin ser interceptada por el mock. Útil para casos donde solo quieres simular ciertas rutas.

import { http, bypass } from 'msw';

export const handler = http.get('https://api.example.com/external', async ({ request }) => {
  // Pasa la petición al servidor real
  const realResponse = await bypass(request);
  return realResponse;
});

Conclusión

msw es una herramienta poderosa y flexible para simular peticiones HTTP en aplicaciones TypeScript. Su enfoque a nivel de Service Worker lo hace único, permitiendo pruebas más realistas sin modificar el código de la aplicación. Con los métodos presentados en esta guía, puedes empezar a crear mocks para REST APIs, GraphQL y más, tanto en el navegador como en Node.js.

Para proyectos más avanzados, msw también soporta GraphQL, WebSockets, y la creación de manejadores dinámicos. Te recomendamos explorar la documentación oficial para descubrir todas las capacidades de la biblioteca.

Recommendations