Contenido del curso
Estrategias de Testing en React
Testing de Flujos de Usuario en React
Testing de Hooks en React
Pruebas de Integración y APIs en React
Reflexiones sobre Testing en React
Pruebas de React con Mock Service Worker y Hooks
Resumen
Probar hooks que consumen APIs sin depender del backend real es uno de los retos más comunes en testing de React. Con Mock Service Worker (MSW) puedes interceptar las requests HTTP y validar que tu hook useOrders se comporte como esperas, usando un servidor simulado en lugar de mocks manuales o spies.
¿Cómo se estructura un test de hook con Mock Service Worker?
La idea es renderizar el hook dentro de un wrapper que provea el contexto necesario, y dejar que MSW intercepte las llamadas reales del hook.
En este enfoque cambias la estrategia respecto a clases anteriores. Antes mockeabas todo: el proveedor de sesión, las rutas y la respuesta del fetch. Ahora solo mockeas la sesión y dejas que MSW responda al endpoint de órdenes como lo haría un servidor real.
Los pasos clave son tres:
- Crear un archivo de test dedicado, por ejemplo
useOrdersMSW.test.tsx, solo con fines educativos. - Importar
describe,ityexpectdesde vitest, yrenderHookdesde testing library. - Encapsular el hook con
SessionProvideryMemoryRoutermediante un wrapper.
¿Qué es Mock Service Worker? Es una utilidad que intercepta requests HTTP a nivel de red y devuelve respuestas simuladas definidas en handlers, sin tocar tu código de producción. [04:30]
¿Por qué se usa un wrapper en lugar de mockear los providers?
Un wrapper permite envolver el hook con los contextos reales que necesita para funcionar. Es más cercano a un test de integración que a un test puramente unitario.
La función renderHook acepta como segundo argumento un objeto con la propiedad wrapper. Ahí pasas un componente que recibe children: React.ReactNode y los envuelve en los providers:
tsx const wrapper = ({ children }: { children: React.ReactNode }) => ( <SessionProvider> <MemoryRouter>{children}</MemoryRouter> </SessionProvider> );
La diferencia con la versión basada en mocks es directa: en aquel caso, renderHook(useOrders) recibía solo el hook porque todo estaba mockeado por fuera. Aquí, en cambio, le pasas { wrapper } para que el hook viva dentro de un entorno realista. [03:10]
¿Cómo se mockea solo la sesión sin tocar las órdenes?
El hook useOrders necesita autenticación para funcionar, así que el useSession sí se mockea. Pero las órdenes ya no: de eso se encarga MSW.
Usas vi.mock apuntando a la ruta del AuthContext, y dentro retornas el módulo real con await vi.importActual más una versión falsa de useSession creada con vi.fn(). Así conservas el SessionProvider original pero controlas qué devuelve el hook de sesión.
Un detalle importante: useSession retorna un valor, no una promesa. Si lo mockeas con mockResolvedValue el test queda colgado en timeout. La solución es usar mockReturnValue para que devuelva directamente el objeto del usuario. [07:50]
¿Cómo se valida que el hook obtuvo la data correcta?
Dentro del it, ejecutas renderHook(useOrders, { wrapper }) y desestructuras result y waitForNextUpdate. El flujo de aserciones cubre dos momentos del ciclo de vida del hook.
Primero verificas el estado inicial:
initialLoadingdebe sertrueantes de que la request responda.- Esto confirma que el hook arranca en estado de carga.
Luego esperas con await waitForNextUpdate() a que MSW responda, y validas el resultado:
result.current.orders.lengthdebe ser1, porque el handler configurado en la clase anterior retorna exactamente una orden.- Si cambias la aserción a
2, el test falla, lo que demuestra que la respuesta viene realmente del servidor simulado.
¿Por qué el test espera una sola orden? Porque el handler de MSW configurado para el endpoint de órdenes retorna un único producto. El número en la aserción debe coincidir con lo que define ese handler. [09:15]
¿Qué hacer cuando el test queda en timeout?
El error timeout waitForNextUpdate suele indicar que el hook nunca avanza de estado. Revisa primero cómo estás mockeando dependencias síncronas como useSession.
La regla es simple: usa mockResolvedValue solo cuando el valor original es una promesa. Para getters que devuelven estado plano, usa mockReturnValue. Confundir ambos rompe la cadena de actualizaciones del hook y bloquea el test.
Con esta base ya puedes probar respuestas exitosas. ¿Y cuándo el servidor falla con un error 500? Cuéntame en los comentarios cómo manejas tú esos casos en tus pruebas.