Pruebas de APIs en Node.js con Jest: guía completa y práctica

Última actualización: marzo 22, 2026
  • Configura Jest en tu proyecto Node.js y apóyate en Supertest para probar APIs Express sin levantar el servidor.
  • Aprovecha los matchers, el soporte asíncrono, la cobertura y los mocks de Jest para cubrir lógica, endpoints y dependencias externas.
  • Aplica TDD y ATDD con Jest, snapshots y tests de aceptación para asegurar que el código cumple los requisitos de negocio.
  • Integra tus tests con pipelines de CI como Drone CI y Docker para validar cada cambio de código de forma automática.

Pruebas de APIs en Node.js con Jest

Si trabajas con back-end en JavaScript, tarde o temprano vas a tener que enfrentarte a probar tus APIs en Node.js de forma automática. Y sí, puedes hacerlo “a mano” con herramientas como Postman, pero cuando el proyecto crece eso es un infierno difícil de mantener. Ahí es justo donde Jest entra en juego y te hace la vida mucho más fácil.

En este artículo vamos a ver cómo probar APIs en Node.js con Jest desde cero hasta un nivel bastante avanzado, mezclando pruebas unitarias, de integración, buenas prácticas, cobertura, mocks, TDD e incluso cómo encajar todo en una integración continua con herramientas como Drone CI. Todo explicado con lenguaje claro, sin rodeos y con ejemplos reales que puedes adaptar a tu propio proyecto.

Por qué merece la pena testear tus APIs en Node.js

Antes de ponerte a escribir código de pruebas como loco, conviene entender por qué es tan importante testear tus endpoints. No es solo una “moda devops”, es una pieza clave del ciclo de vida de desarrollo de software (SDLC) moderno.

Las APIs de back-end son el centro de cualquier aplicación: atienden peticiones, gestionan lógica de negocio, hablan con bases de datos y servicios externos. Si algo se rompe ahí, se cae media plataforma. Tener una buena batería de tests te permite detectar errores pronto, evitar regresiones al hacer refactors y desplegar con mucha más tranquilidad.

En entornos nativos en la nube y con equipos grandes, apoyarse en pruebas automatizadas integradas en pipelines de integración continua (CI) no es un lujo, es una necesidad. Sistemas como Drone CI pueden ejecutar tus suites de Jest en cada push para avisarte al instante en cuanto algo deja de funcionar como debe.

Al final, todo esto va de asegurarse de que tu código sigue funcionando cuando introduces cambios hoy, mañana y dentro de seis meses. Y la forma más efectiva de conseguirlo es escribir buenas pruebas unitarias y de integración orientadas a tus APIs.

Qué es Jest y por qué se usa tanto para Node.js

Framework Jest para pruebas en JavaScript

Jest es un framework de testing para JavaScript creado por Facebook y pensado para funcionar prácticamente sin configuración (“zero config”) en la mayoría de casos. Aunque se hizo muy popular en el ecosistema React, encaja de maravilla para probar código Node.js, tanto lógica pura como APIs HTTP.

Una de sus grandes ventajas es que integra en una sola herramienta el runner de pruebas, el sistema de aserciones (matchers) y el soporte para mocks. Con otros stacks tienes que combinar Mocha, Chai, Sinon, etc. Aquí, con Jest, lo tienes todo en la misma casa, lo que acelera muchísimo el arranque de cualquier proyecto de pruebas.

Jest admite distintos tipos de pruebas: unitarias, de integración, pruebas de snapshots e incluso tests E2E cuando se integra con otras librerías como Puppeteer. Y además trae soporte nativo para pruebas asíncronas, algo esencial cuando hablamos de APIs y peticiones HTTP.

Otro punto fuerte es su feedback rápido: modo watch, reporting de cobertura integrado y mensajes de error muy legibles. Todo esto anima a que el equipo realmente use los tests en el día a día y no solo como algo “que hay que hacer para la auditoría”.

Preparar un proyecto Node.js para probar con Jest

Configuración de Jest en un proyecto Node.js

Lo primero es tener Node.js instalado desde la web oficial y un proyecto inicializado con npm init -y. Si necesitas montar un entorno local, puedes aprender a configurar un servidor local de pruebas y dejar todo listo para ejecutar tu suite. A partir de ahí, puedes añadir Jest como dependencia de desarrollo usando el gestor de paquetes que prefieras.

En el caso de npm, bastaría con algo como npm install --save-dev jest. Con Yarn podrías hacer yarn add --dev jest. En ambos casos, Jest se añadirá a tu package.json como dependencia de desarrollo, listo para ser usado.

Después necesitas indicar a npm que el comando de test use Jest. Para ello, en package.json modificas el script "test": "jest", sustituyendo la típica línea que muestra el mensaje de “Error: no test specified”. A partir de ese momento, ejecutar npm test o yarn test lanzará Jest.

Si quieres ir un paso más allá, Jest ofrece un comando interactivo para generar un fichero de configuración básico. Al ejecutarlo, te hace unas preguntas sobre tu proyecto (entorno, tipo de módulos, etc.) y crea un archivo de configuración con las opciones recomendadas y una breve descripción de cada una, lo que viene muy bien para proyectos más serios.

Primera toma de contacto: prueba sencilla en Jest

Ejemplo de pruebas unitarias con Jest

Antes de meternos con APIs, viene bien ver un ejemplo muy simple de prueba unitaria con Jest. Imagina que tienes una función que suma dos números. Creas un archivo sum.js con algo tipo module.exports = (a, b) => a + b y luego un archivo sum.test.js con la prueba.

Dentro del test, usas la API global de Jest: test() para definir el caso y expect() junto con un matcher como toBe() para comparar el resultado real con el esperado. Al ejecutar npm test, Jest interpreta ese archivo, lanza la función y valida la aserción; si todo está correcto, te mostrará un mensaje indicando que has pasado tu primer test.

Desde la línea de comandos también puedes controlar Jest de forma más avanzada: filtrar por nombre de archivo, usar un fichero de configuración concreto o mostrar notificaciones nativas del sistema una vez se termina la ejecución. Toda esa personalización se gestiona a través de las opciones del CLI de Jest.

Si en tu proyecto utilizas Babel, también puedes configurarlo para que Jest transpile el código aprovechando el preset adecuado. Creando un babel.config.js en la raíz e incluyendo presets como @babel/preset-env y, si usas TypeScript, @babel/preset-typescript, puedes probar código moderno sin problemas con la versión de Node que tengas instalada.

Configurar y probar una API Express con Jest y Supertest

El caso típico al trabajar con Node.js es tener un servidor Express. Lo habitual es montar tu aplicación en un fichero como app.js o server.js y exponer el objeto de aplicación para poder importarlo desde tus tests. De este modo, puedes simular peticiones HTTP en memoria sin levantar realmente el servidor.

Para testear endpoints HTTP de forma cómoda se usa mucho la librería Supertest. Esta herramienta envuelve tu app de Express y te deja encadenar métodos como .get(), .post(), etc., para realizar peticiones y luego inspeccionar el resultado (estado, cabeceras, cuerpo de la respuesta…).

Un test básico con Jest y Supertest podría tener esta estructura: importas la aplicación Express, creas una petición GET a la ruta que quieres comprobar y usas await para esperar la respuesta y expect() para verificar que el código de estado sea 200 o que el cuerpo devuelva la estructura que necesitas.

Por ejemplo, si tu endpoint raíz devuelve un JSON con { mensaje: "Hola mundo" }, puedes comprobarlo con matchers como toEqual() para comparar el objeto completo. La combinación Jest + Supertest te deja cubrir desde pruebas muy sencillas hasta escenarios complejos con autenticación, validaciones y distintas ramas de código.

Si usas Express Validator u otra librería de validación, es perfectamente posible montar tests específicos para asegurarte de que los errores se devuelven correctamente cuando las entradas no cumplen las reglas. En este tipo de pruebas resulta muy útil verificar tanto el código de estado (por ejemplo, 400) como el contenido concreto del mensaje de error.

Fundamentos de pruebas unitarias y TDD con Jest

Más allá de las APIs, es fundamental dominar las pruebas unitarias como herramienta diaria de trabajo. Una prueba unitaria es un fragmento pequeño de código que comprueba una función o método concreto, centrándose en la lógica interna y no en la interfaz de usuario ni en el rendimiento.

Mucha gente asocia estas prácticas con el desarrollo guiado por pruebas (TDD). La idea aquí es muy sencilla: primero escribes el test, compruebas que falla, implementas la mínima lógica necesaria para que pase, validas que ya funciona y después refactorizas. Luego repites el ciclo con la siguiente funcionalidad. Esto obliga a que el código se ajuste exactamente a los requisitos expresados por los tests.

Un ejemplo muy típico para practicar consiste en crear un módulo como calculator.js con funciones de suma, resta y multiplicación, y un fichero calculator.test.js donde se definen varios casos de prueba usando describe() para agrupar y test() para cada operación. Dentro de cada test se siguen las fases clásicas: preparar datos, ejecutar la función y afirmar el resultado con expect().toBe().

Este tipo de ejercicios, aunque parezcan muy básicos, ayudan a interiorizar cómo escribir tests legibles y mantenibles, y cómo organizar tu código en funciones pequeñas y testeables, algo que luego trasladas de manera natural a tus APIs y a tu lógica de negocio real.

Matchers, ciclos de vida y pruebas asíncronas en Jest

Uno de los puntos clave de Jest es su colección de matchers para comparar valores esperados con resultados reales. Para valores primitivos es habitual usar toBe, mientras que para objetos y arrays complejos suele utilizarse toEqual, que hace comparaciones profundas.

También cuentas con matchers numéricos como toBeLessThan, toBeGreaterThan o sus variantes con “OrEqual”, muy útiles cuando quieres comprobar rangos o condiciones relativas. Para valores booleanos o de control de flujo dispones de toBeTruthy, toBeFalsy, toBeNull o toBeUndefined.

Cuando trabajas con colecciones, Jest te ofrece matchers como toContain o toHaveLength, ideales para validar elementos en listas o el número de resultados devueltos por un endpoint de tu API. Para cadenas de texto puedes usar toMatch con expresiones regulares y también comprobar longitudes u otros criterios más específicos.

A nivel de ciclo de vida, Jest incorpora funciones como beforeAll, afterAll, beforeEach y afterEach para ejecutar lógica de preparación o limpieza antes o después de cada test o de todo un conjunto. Esto es muy útil, por ejemplo, para levantar y tumbar conexiones, poblar una base de datos temporal o resetear mocks.

En cuanto a código asíncrono, Jest soporta callbacks, promesas y async/await. Con APIs REST esto es fundamental, ya que la mayoría de operaciones implican I/O asíncrono. Puedes devolver la promesa desde el test, utilizar await dentro de funciones marcadas como asíncronas o llamar a done cuando termine una callback; lo importante es indicarle a Jest cuándo ha concluido realmente la prueba para que no se dé por finalizada antes de tiempo.

Medir la cobertura de tus tests con Jest

Para saber qué parte de tu código estás cubriendo realmente, Jest ofrece un modo de ejecución con informe de cobertura. Normalmente se activa añadiendo un script tipo test:coverage en tu package.json que ejecute Jest con la opción adecuada.

Al lanzar ese comando, Jest genera un informe en consola mostrando porcentaje de sentencias, ramas, funciones y líneas cubiertas por archivo. Además, crea una carpeta coverage con un reporte HTML (por ejemplo, en coverage/lcov-report/index.html) donde puedes ver los resultados de forma visual y navegar por cada fichero.

Este tipo de análisis es muy práctico para identificar módulos o rutas de tu API que no se han probado en absoluto (a veces aparecen con 0 % de cobertura) o detectar ramas concretas de código que nadie está tocando en las pruebas.

Combinado con el modo --watchAll, Jest puede vigilar constantemente tus cambios de código y relanzar los tests al vuelo, actualizando también la cobertura a medida que añades o refinas tus casos de prueba.

Mocks, tests de integración y E2E con Jest

En muchos escenarios no quieres que tus tests llamen realmente a servicios externos: APIs de terceros, bases de datos remotas o incluso tu propio back-end en otro entorno. Para esto Jest aporta un potente sistema de mocks y contract testing que te permite simular dependencias y centrar el test en la lógica que quieres validar.

Puedes crear ficheros de mocks locales y dejar que Jest los use automáticamente, o bien definirlos de forma explícita en los tests. Un caso típico es simular librerías como Axios: cuando tu componente o módulo llame a Axios, Jest redirige esas llamadas al mock, devolviendo datos predefinidos y evitando peticiones reales.

Esto se aplica también a pruebas de frameworks de frontend como Vue.js, donde se utilizan herramientas como Vue Test Utils junto con Jest para montar componentes. Ahí entran funciones como mount o shallowMount, que permiten renderizar componentes completos o sin sus hijos, generando un wrapper (un mock de la instancia de Vue) sobre el que puedes hacer aserciones.

En componentes Vue puedes probar propiedades, datos, métodos, eventos y elementos del DOM accediendo a ellos mediante selectores CSS u ofreciendo atributos específicos como data-testid. Además, puedes usar propsData o setProps para pasar propiedades a los componentes y comprobar cómo reaccionan.

Para pruebas de tipo E2E existe la opción de integrar Jest con Puppeteer, que controla un navegador headless y permite simular la interacción real de un usuario: navegar por páginas, disparar eventos, rellenar formularios, comprobar elementos del DOM, hacer capturas de pantalla o incluso analizar aspectos de SEO. Los tests siguen ejecutándose dentro del runner de Jest, aprovechando su filosofía y su sistema de aserciones.

Snapshots, TDD y ATDD en el flujo de trabajo

Otro recurso interesante que ofrece Jest son los snapshots, que permiten capturar el estado de una salida en un momento dado (por ejemplo, la representación de un componente o la estructura de un objeto) y compararlo automáticamente en futuras ejecuciones.

La primera vez que ejecutas un test con snapshot, Jest crea una carpeta de snapshots con los datos almacenados. En las ejecuciones siguientes compara la salida actual con esa captura. Si cambia algo, el test falla, lo que sirve para detectar modificaciones inesperadas. Cuando el cambio es intencionado, puedes actualizar el snapshot con un flag específico (como la opción -u).

Incluso puedes definir excepciones dentro de toMatchSnapshot() para ignorar ciertos campos que sabes que van a variar, como fechas o identificadores generados dinámicamente. Esto hace que los snapshots sean más robustos y menos “frágiles” ante cambios inevitables.

En cuanto al enfoque metodológico, muchas personas combinan TDD (Test-Driven Development) con ATDD (Acceptance Test-Driven Development). Primero se definen tests de aceptación que reflejan requisitos de negocio acordados con el cliente: entradas y salidas esperadas para ciertas funcionalidades clave.

Esos tests de aceptación se traducen a pruebas ejecutables, tras lo cual se aplica TDD para ir implementando el código paso a paso. De esta manera, cuando los tests pasan, tienes la garantía de que el software satisface los requisitos que se definieron al inicio. En algunos ejemplos se ve cómo primero se escriben los tests para algo como un módulo de contactos o una cuenta bancaria, y luego se va construyendo la implementación commit a commit siguiendo esta filosofía.

TypeScript, bundlers y ESLint con Jest

A día de hoy es muy habitual que los proyectos Node.js utilicen TypeScript, bundlers como webpack o Parcel y herramientas de linting como ESLint. La buena noticia es que Jest juega bastante bien con todo este ecosistema, siempre que lo configures correctamente.

Para TypeScript tienes dos vías principales: usar Babel con @babel/preset-typescript para hacer solo la transpilación, o recurrir a ts-jest, que actúa como preprocesador específico para Jest y permite una integración más ajustada al compilador de TypeScript.

Si eliges Babel, debes tener claro que Jest no realizará comprobación de tipos en tiempo de ejecución; para eso seguirás necesitando lanzar tsc aparte o incluirlo en tu proceso de build. Con ts-jest puedes definir una configuración dedicada para que Jest entienda TypeScript directamente.

En cuanto a bundlers, en la mayoría de proyectos no hace falta nada especial, salvo que tengas reglas de resolución de módulos muy personalizadas o generes archivos especiales. Para webpack, Jest dispone de guías específicas que explican cómo adaptarlo; con Vite la cosa es más delicada, ya que no hay soporte oficial directo y hay que recurrir a librerías externas como vite-jest (con ciertas limitaciones de versión). En algunos casos es más cómodo usar alternativas pensadas para Vite, como Vitest.

Respecto a ESLint, basta con asegurarte de que el linter conoce las globals de Jest. Puedes hacerlo importando describe, it, test, etc., desde @jest/globals en tus archivos de pruebas o activando el entorno jest en la configuración de ESLint. Otra opción es instalar eslint-plugin-jest, que añade reglas específicas para trabajar con tests en este framework.

Integración continua de tests Jest con Drone CI y Docker

Una vez que tienes una buena batería de pruebas unitarias e integradas con Jest, el siguiente paso natural es automatizarlas dentro de un pipeline de integración continua. Así, cada vez que alguien haga push a la rama principal, se ejecutarán los tests y se avisará de fallos antes de llegar a producción.

Herramientas como Drone CI encajan muy bien en este escenario. Puedes preparar un fichero de configuración .drone.yml donde definas un pipeline simple que use una imagen de Node, instale las dependencias del proyecto y ejecute npm test. A partir de ahí, cada nueva build revisa el código contra tu suite de Jest.

Drone CI se integra con repositorios como GitHub, de manera que al activar un repo y configurar los secretos necesarios (por ejemplo, credenciales de Docker Hub), el sistema puede construir contenedores y ejecutar tests según tus pasos definidos. La interfaz web muestra el estado de cada build, los logs, y permite disparar nuevas ejecuciones cuando lo necesites.

Para quienes quieren algo todavía más rápido en local, existe una extensión de Drone para Docker Desktop. Con un único comando puedes instalarla y luego, desde la interfaz de Docker, importar pipelines apuntando a repos que ya tengan un .drone.yml. Solo necesitas indicar secretos y variables de entorno si hacen falta y lanzar la canalización con un botón.

Este tipo de integración ayuda a que los equipos detecten errores antes de que lleguen al usuario final, manteniendo un flujo de trabajo donde escribir tests con Jest forma parte natural de la vida del proyecto, no una tarea aislada que se deja para el final del sprint.

Si pones todo esto en práctica —buenas pruebas unitarias con Jest, cobertura razonable, integración con Supertest para tus APIs de Node.js, mocks donde toque, snapshots y TDD/ATDD cuando proceda, además de integrarlo en un pipeline de CI como Drone— acabarás con un sistema de testing sólido que te ahorrará bugs, sustos y muchas horas de depuración a largo plazo.

plataforma de ingeniería de calidad con agentes de IA
Artículo relacionado:
Plataforma de ingeniería de calidad con agentes de IA: guía completa