Mocks MSW - patrones de diseño y arquitectura de mocks
Mocks MSW - patrones de diseño y arquitectura de mocks
- MSW Mocks service worker
- Mocks MSW - patrones de validación y depuración
- Testing
- TDD - Test Driven Development
- profiler
🧩 Objetivo
Definir estrategias avanzadas para estructurar, escalar y mantener mocks MSW en proyectos grandes, garantizando modularidad, trazabilidad y fácil mantenimiento.
Estos patrones se aplican a entornos con múltiples endpoints, microservicios o flujos de testing complejos.
🧠 Conceptos Clave
- Arquitectura de Mocks: Organización lógica de handlers y servidores de prueba.
- Separación por Dominio: Agrupar mocks según áreas funcionales (auth, users, products…).
- Composición Modular: Reutilizar handlers comunes mediante
composeHandlers(). - Tipado y Validación: Usar TypeScript para garantizar consistencia entre mocks y tipos de API.
- Escalabilidad: Facilitar crecimiento del proyecto sin romper la estructura existente.
- Sincronía con la API real: Mantener paridad con esquemas y rutas reales del backend.
🏗️ Estructura Recomendada de Carpetas
src/
└── mocks/
├── handlers/
│ ├── auth.ts
│ ├── users.ts
│ ├── products.ts
│ └── index.ts
├── factories/
│ ├── userFactory.ts
│ └── productFactory.ts
├── utils/
│ ├── delay.ts
│ └── logger.ts
├── browser.ts
├── server.ts
└── setupTests.ts
💡 Consejo: Cada archivo en handlers/ debe exponer un array de mocks agrupados por dominio.
🧩 Patrón 1 — Composición Modular de Handlers
Descripción
Agrupa y combina handlers desde diferentes dominios en un único punto de entrada.
Ejemplo
// src/mocks/handlers/index.ts
import { authHandlers } from './auth';
import { userHandlers } from './users';
import { productHandlers } from './products';
export const handlers = [
...authHandlers,
...userHandlers,
...productHandlers,
];
🧠 Facilita mantener independencia de módulos y evita un único archivo monolítico.
🧩 Patrón 2 — Mock Factories Reutilizables
Descripción
Genera datos dinámicos de prueba con funciones puras o librerías como Faker.js.
Ejemplo
// src/mocks/factories/userFactory.ts
import { faker } from '@faker-js/faker';
export const createMockUser = (overrides = {}) => ({
id: faker.number.int(),
name: faker.person.fullName(),
email: faker.internet.email(),
role: 'user',
...overrides,
});
📦 Ideal para mantener consistencia entre diferentes tests que requieren usuarios simulados.
🧩 Patrón 3 — Handlers con Tipado Estricto
Descripción
Asegura coherencia entre los tipos usados en mocks y en las interfaces de API.
Ejemplo
import { http, HttpResponse } from 'msw';
import type { User } from '@/types';
export const userHandlers = [
http.get('/api/users', () => {
const users: User[] = [{ id: 1, name: 'Eduardo', email: 'edu@dev.io' }];
return HttpResponse.json(users);
}),
];
🔒 Evita mocks obsoletos o con propiedades incorrectas.
🧩 Patrón 4 — Jerarquía de Handlers por Contexto
Descripción
Clasifica handlers según el entorno: base, error, auth, integration, etc.
Ejemplo
// src/mocks/handlers/context/index.ts
export { baseHandlers } from './base';
export { errorHandlers } from './error';
export { authHandlers } from './auth';
Luego combínalos dinámicamente:
export const handlers = [
...baseHandlers,
...(process.env.MOCK_ERROR ? errorHandlers : []),
];
⚙️ Permite cambiar comportamientos globales sin modificar código de producción.
🧩 Patrón 5 — Reutilización con Utilidades Compartidas
Descripción
Centraliza funciones comunes como delays, logs o respuestas estándar.
Ejemplo
// src/mocks/utils/delay.ts
export const simulateDelay = (ms = 500) =>
new Promise((resolve) => setTimeout(resolve, ms));
// uso dentro del handler
await simulateDelay(800);
return HttpResponse.json({ status: 'ok' });
💡 Mejora legibilidad y uniformidad del tiempo de respuesta en todos los tests.
🧩 Patrón 6 — Configuración de Entornos Diferenciados
Descripción
Permite inicializar distintos conjuntos de handlers según el entorno (dev, test, staging).
Ejemplo
// src/mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
const env = process.env.NODE_ENV;
export const server = setupServer(
...(env === 'test' ? handlers.test : handlers.dev)
);
🔧 Facilita tener respuestas distintas sin duplicar lógica.
🧩 Patrón 7 — Mock Layer Composition
Descripción
Combina respuestas simuladas con datos reales (parcial mocking).
Ejemplo
http.get('/api/settings', async () => {
const response = await fetch('/__real__/settings');
const realData = await response.json();
return HttpResponse.json({ ...realData, mode: 'mocked' });
});
🧬 Útil para entornos híbridos donde parte de la API real está disponible.
🧩 Patrón 8 — Documentación de Mocks
Descripción
Cada handler debe incluir un comentario de propósito y dependencias.
Ejemplo
// [users.ts]
// Mock de /api/users
// Dependencias: userFactory, authHandlers
export const userHandlers = [
http.get('/api/users', () => HttpResponse.json([])),
];
📘 Permite a nuevos desarrolladores entender fácilmente el alcance del mock.
🧩 Patrón 9 — Convenciones de Nombres
| Tipo de archivo | Sufijo recomendado | Ejemplo |
|---|---|---|
| Handler por dominio | *.handlers.ts |
users.handlers.ts |
| Factory de datos | *.factory.ts |
user.factory.ts |
| Utilidad compartida | *.utils.ts |
delay.utils.ts |
| Configuración global | server.ts |
server.ts |
🪶 Establece coherencia y facilita búsquedas en grandes repositorios.
🧩 Patrón 10 — Testing de Mocks en Aislamiento
Descripción
Valida que los mocks respondan correctamente antes de integrarlos en tests de UI.
Ejemplo
import { handlers } from '@/mocks/handlers';
import { setupServer } from 'msw/node';
const testServer = setupServer(...handlers);
testServer.listen();
test('endpoint /api/users mockeado', async () => {
const res = await fetch('/api/users');
const data = await res.json();
expect(data).toBeInstanceOf(Array);
});
✅ Permite garantizar calidad de los mocks como si fueran un microservicio.
🔍 Diagnóstico Rápido
| Problema | Causa | Solución |
|---|---|---|
| Handlers duplicados | Importación circular | Centralizar en handlers/index.ts |
| Mock no intercepta peticiones | URL incorrecta o prefijo | Verificar coincidencia exacta con endpoint |
| Demasiada lógica en handlers | Falta de factorías o utils | Mover generación de datos a /factories |
| Mock no actualiza con cambios | Cache del Service Worker | Ejecutar navigator.serviceWorker.getRegistrations() |
| Dificultad al escalar mocks | Estructura monolítica | Separar por dominio y entorno |
🔗 Referencias
¿Te gusta este contenido? Suscríbete vía RSS