Contenido del curso

Pruebas a la API de Fake Store

Pruebas en Entornos de Desarrollo Avanzados

Mocking de Nodemailer en pruebas E2E

Resumen

Las pruebas end-to-end buscan validar el flujo completo de una aplicación, pero hay servicios externos donde no tienes control y conectarte de verdad sería costoso o imposible. Aquí entra el mocking en pruebas end-to-end, una técnica para emular respuestas de terceros como Nodemailer, APIs de Microsoft Cognitive Services o cualquier servicio que cobre por request.

¿Por qué hacer mocking en una prueba end-to-end?

En teoría, una prueba end-to-end corre con todos los artefactos reales de la aplicación. Para la base de datos puedes levantar un contenedor de Docker, manipular un set de datos y consultar resultados directamente. Pero con servicios de terceros, esa estrategia se rompe.

No puedes conectarte a la base de datos de Gmail para verificar si un correo llegó. Tampoco puedes invocar una API de pago en cada corrida sin gastar recursos o arriesgarte a que te baneen. En esos casos, el mocking deja de ser opcional.

¿Qué es el mocking en pruebas? Es reemplazar la implementación real de una función o servicio por una versión simulada que devuelve respuestas controladas, sin ejecutar el código original.

Esta práctica fue introducida en la clase del minuto [5:30], donde se explica que el concepto se profundiza en el curso de Introducción al testing con JavaScript.

¿Qué endpoint vamos a probar y dónde aparece Nodemailer?

El endpoint bajo prueba es el de recovery dentro del módulo de autenticación. Su flujo es claro:

  • Recibe un email y verifica que el usuario exista; si no, responde 401.
  • Firma un JWT para el proceso de recuperación de contraseña.
  • Guarda ese token en el campo recovery token de la base de datos.
  • Llama a sendMail de Nodemailer usando SMTP para enviar el correo.

El problema vive en el último paso. Nodemailer usa una capa de transporte SMTP con usuario y contraseña, y no tienes forma de comprobar que el correo realmente llegó. Si dejas el código tal cual, cada corrida de pruebas dispara un envío real, lo que consume recursos y puede terminar en un baneo.

¿Qué pasa si corres la prueba sin mock?

Al ejecutar npm run end-to-end sin mockear, el endpoint devuelve un 500. Imprimiendo el body con console.log aparece el mensaje de Gmail diciendo que el usuario y password no son aceptados. La conclusión es directa: o configuras credenciales reales y mandas correos basura en cada test, o haces mocking.

¿Cómo mockear Nodemailer con jest.fn y jest.mock?

La estrategia tiene dos piezas. Primero, una función espía para sendMail. Segundo, un mock del módulo completo de Nodemailer que reemplace createTransport.

El espía se crea así:

javascript const mockSendMail = jest.fn();

Luego se mockea el módulo completo. La clave es que createTransport debe devolver un objeto con la propiedad sendMail, porque así funciona la librería real:

javascript jest.mock('nodemailer', () => ({ createTransport: jest.fn().mockImplementation(() => ({ sendMail: mockSendMail, })), }));

Lo que estás diciendo es: cuando Nodemailer ejecute createTransport, no corras el código real, devuélveme un transporter falso cuyo sendMail es mi espía. Este patrón aparece explicado en el minuto [6:45].

¿Cómo limpiar el mock entre pruebas?

Una buena práctica es limpiar el mock antes de cada bloque para evitar que el estado de una prueba contamine a la siguiente:

javascript beforeAll(() => { mockSendMail.mockClear(); });

Esto previene comportamientos cruzados y mantiene cada test aislado.

¿Cómo controlar la respuesta del mock y verificar que se llamó?

Antes del await request(...).post(...), defines qué va a resolver el espía. Como sendMail retorna una promesa, usas mockResolvedValue:

javascript mockSendMail.mockResolvedValue(true);

Ojo con el nombre exacto del método. En el video, un typo (mockResolveValue sin la d) hace fallar la prueba en el minuto [11:20]. La forma correcta es mockResolvedValue, con la d minúscula.

Después de ejecutar el endpoint, verificas que el mock fue invocado. Aquí entran los spies:

javascript expect(mockSendMail).toHaveBeenCalled();

Esto garantiza que aunque estés emulando, el código de producción sí intentó enviar el correo. Si alguien comenta la línea de sendMail, la prueba debe romperse.

¿Qué es un spy en testing? Es una función que registra cuándo y cómo fue llamada, lo que te permite verificar que tu código ejecutó la operación esperada sin importar el resultado real.

¿Qué casos de prueba cubre el endpoint de recovery?

El set de pruebas para POST /recovery incluye dos escenarios principales:

  1. Enviar un email que no existe en la base de datos y esperar un 401.
  2. Enviar el email de un usuario real (consultado con User.find sobre el administrador) y esperar un 200 con body.message igual a Mail enviado.

El segundo caso es el que requiere el mock activo, porque sin él la respuesta sería 500 por la falla de SMTP.

¿Cuándo es obligatorio mockear y cuándo no?

La regla práctica es simple. Si controlas el recurso, como una base de datos en un contenedor Docker, mantén la prueba lo más real posible. Si el recurso es de terceros (Gmail, APIs cognitivas, pasarelas de pago), mockea siempre. Llamar a esas APIs en cada corrida gasta dinero, consume cuotas y puede romper la suite por fallos ajenos a tu código.

Con el flujo de mocking funcionando, el siguiente paso natural es llevar estas pruebas a un pipeline de integración continua con GitHub Actions. ¿Has integrado Nodemailer u otro servicio externo en tus pruebas? Cuéntame cómo lo resolviste.