Las pruebas de software son vitales para garantizar que tus aplicaciones funcionan según lo esperado, especialmente cuando introduces cambios. Detectar y corregir errores en una fase temprana del desarrollo es crucial para mantener un código resistente y de alta calidad.
De las muchas herramientas y frameworks disponibles para las pruebas de JavaScript, Jest es una de las más populares. Jest, un producto de Meta, cuenta con amplias capacidades de comprobación para aplicaciones JavaScript y las construidas con marcos JavaScript.
Exploremos el framework Jest, sus características y la mejor forma de integrarlo en tu flujo de trabajo de desarrollo.
¿Qué es Jest?
Jest es un framework flexible y sencillo de utilizar. Además de sus funciones básicas de comprobación de JavaScript, ofrece configuraciones y complementos para admitir la comprobación de aplicaciones basadas en Babel, webpack, Vite, Parcel o TypeScript.
Jest ha sido ampliamente adoptado por los desarrolladores y cuenta con una serie de complementos creados y mantenidos por la comunidad. Destaca por su facilidad de uso: Las pruebas de JavaScript no requieren configuraciones ni plugins adicionales. Pero también puedes realizar pruebas más avanzadas – como probar frameworks JavaScript – utilizando algunas opciones de configuración adicionales.
Cómo Configurar Jest para Tu Proyecto JavaScript
Repasemos como configurar Jest en un proyecto JavaScript existente.
Requisitos previos
Para seguir este tutorial, asegúrate de que tienes lo siguiente:
- Node.js instalado.
- npm (que ya forma parte de Node.js) o Yarn instalados.
- El paquete npm Jest instalado.
Instala el paquete Jest
- Si aún no tienes un proyecto para seguir este tutorial, utiliza este repositorio como punto de partida.
La rama starter-files
te proporciona una base para construir la aplicación mientras sigues el tutorial. Consulta la rama main
para ver el código de este tutorial y cotejar tu código.
- Para instalar Jest con npm, ve al directorio del proyecto en tu terminal y ejecuta el siguiente comando:
npm install --save-dev jest
La opción --save-dev
indica a npm que instale el paquete en devDependencies
, que contiene las dependencias que necesitas para el desarrollo.
Configura Jest
Aunque Jest suele funcionar sin configuración adicional, hay dos formas de ampliar su potencia: en el archivo package.json y mediante un archivo de configuración de Jest.
Configurar Jest en package. json
En tu archivo package.json, añade un objeto llamado jest
con las propiedades que se muestran a continuación:
{
…
"jest": {
"displayName": "Ecommerce",
"globals": {
"PROJECT_NAME": "Ecommerce TD"
},
"bail": 20,
"verbose": true
},
}
Durante la prueba, Jest busca en este objeto y aplica estas configuraciones. Puedes ver opciones adicionales en la página de configuraciones de Jest, pero las propiedades de este objeto incluyen:
displayName
– Jest añade el valor de esta propiedad como etiqueta a los resultados de tus pruebas.globals
– Contiene un valor de objeto para definir las variables globales disponibles en tus entornos de prueba.bail
– Por defecto, Jest ejecuta todas las pruebas y muestra los errores en los resultados.bail
indica a Jest que detenga la ejecución tras un número determinado de fallos.verbose
– Cuando se establece entrue
, muestra informes de pruebas individuales durante la ejecución de la prueba.
Configurar Jest en un archivo de configuración
También puedes configurar Jest en un archivo jest.config.js. Jest también admite las extensiones .ts, .mjs, .cjs y .json. Al ejecutar las pruebas, Jest busca estos archivos y aplica la configuración del archivo que encuentra.
Por ejemplo, considera este archivo jest.config.js:
const config = {
displayName: "Ecommerce",
globals: {
"PROJECT_NAME": "Ecommerce TD"
},
bail: 20,
verbose: true
}
module.exports = config;
El código exporta un objeto de configuración Jest con las mismas propiedades que el ejemplo anterior.
También puedes utilizar un archivo personalizado que contenga un objeto de configuración serializable en JSON y pasar la ruta del archivo a la opción --config
al ejecutar tus pruebas.
Crea un archivo de prueba básico
Con Jest configurado, crea tus archivos de prueba. Jest revisa los archivos de prueba de tu proyecto, los ejecuta y proporciona los resultados. Los archivos de prueba suelen seguir un formato como [name].test.js o [name]-test.js. Este patrón facilita tanto a Jest como a tu equipo la identificación de tus archivos de prueba.
Considera un archivo string-format.js que tenga el siguiente código:
function truncate(
str,
count,
withEllipsis = true
) {
if (str.length < = count)
return str
const substring = str.substr(0, count)
if (!withEllipsis)
return substring
return substring + '...'
}
module.exports = { truncate }
La función truncate()
trunca las cadenas hasta una longitud determinada con la opción de añadir una elipsis.
Escribe la prueba
- Crea un archivo de prueba llamado string-format.test.js.
- Para mantener tus archivos organizados, coloca string-format.test.js en el mismo directorio en el que tienes el archivo string-format.js o en un directorio de prueba específico. Independientemente de dónde esté tu archivo de prueba dentro del proyecto, Jest lo encuentra y lo ejecuta. Con Jest, puedes probar tus aplicaciones en varios escenarios.
- Escribe una prueba básica en string-format.test.js de la siguiente manera::
const { truncate } = require('./string-format')
test('truncates a string correctly', () = > {
expect(truncate("I am going home", 6)).toBe('I am g...')
})
El caso de prueba tiene la descripción truncates a string correctly
. Este código utiliza la función expect
proporcionada por Jest, que comprueba si un valor coincide con el resultado esperado.
El código pasa truncate("I am going home", 6)
como argumento a expect
. Este código prueba el valor devuelto al llamar a truncate
con los argumentos "I am going home"
y 6
. La llamada a expect
devuelve un objeto expectativa, que ofrece acceso a las coincidencias de Jest.
También contiene el comparador toBe
, que tiene "I am g…"
como argumento. El emparejador toBe
comprueba la igualdad entre los valores esperados y los reales.
Ejecutar la prueba
Para ejecutar tus pruebas, define el comando jest
.
- En el archivo package.json de tu proyecto, añade este script
test
:
"scripts": {
"test": "jest"
}
- Ahora ejecuta
npm run test
,npm test
, onpm t
en tu terminal. Ejecuta Jest para el proyecto.
Cuando ejecutes las pruebas, éste será el resultado:
- En string-format.js, si añades un punto de más para romper el código y ejecutar la prueba, ésta falla:
Este resultado sugiere que has roto la función truncate
o has hecho actualizaciones que requieren actualizar las pruebas.
Cómo Escribir Pruebas con Jest
Sintaxis de las pruebas Jest
La sintaxis propia de Jest es sencilla de utilizar. Jest expone métodos y objetos globales a tu proyecto para escribir pruebas. Algunos de sus términos fundamentales son describe
, test
, expect
, y matchers.
describe
: Esta función agrupa pruebas relacionadas en un archivo.test
: Esta función ejecuta la prueba. Es un alias deit
. Contiene aserciones para los valores que quieres probar.expect
: Esta función declara las aserciones para varios valores. Proporciona acceso a emparejadores para varias formas de aserciones.- Matchers: Te permiten afirmar un valor de varias formas. Puedes afirmar la igualdad de valores, la igualdad booleana y la igualdad contextual (como si una matriz contiene el valor).
Para utilizarlos, considera el siguiente ejemplo:
- Sustituye la prueba del archivo string-format.test.js por el siguiente código:
describe("all string formats work as expected", () = > {
test("truncates a string correctly", () = > {
expect(
truncate("I am going home", 6)
).toBe("I am g...")
})
})
- Ejecuta el código.
El resultado debe ser el siguiente:
La captura de pantalla muestra que la etiqueta de la función describe
crea un bloque. Aunque describe
es opcional, agrupar las pruebas en un archivo con más contexto resulta útil.
Organizar las pruebas en conjuntos de pruebas
En Jest, un caso de prueba consta de la función test
, la función expect
y un emparejador. Una colección de casos de prueba relacionados es un conjunto de pruebas. En el ejemplo anterior, string-format .test.js es un conjunto de pruebas que incluye un caso de prueba para comprobar el archivo string-format.js.
Supongamos que tienes más archivos en tu proyecto, como file-operations.js, api-logger.js y number-format.js. Puedes crear conjuntos de pruebas para estos archivos, como file-operations.test.js, api-logger.test.js y number-format.test.js.
Escribir aserciones sencillas con comparadores Jest
Hemos explorado un ejemplo de uso del comparador toBe
. Las aserciones con otros comparadores Jest incluyen:
toEqual
– Para comprobar la igualdad «profunda» en instancias de objetos.toBeTruthy
– Para comprobar si un valor es verdadero en un contexto booleano.toBeFalsy
– Para comprobar si un valor es falso en un contexto booleano.toContain
– Para comprobar que una matriz contiene un valor.toThrow
– Para comprobar si una función invocada produce un error.stringContaining
– Para comprobar que una cadena contiene una subcadena.
Veamos algunos ejemplos en los que se utilizan algunos de estos emparejadores.
Por ejemplo, puedes esperar que una función o código devuelva un objeto con propiedades y valores específicos.
- Utiliza el fragmento de código siguiente para probar esta funcionalidad. En este caso, quieres afirmar que el objeto devuelto es igual al objeto esperado.
expect({
name: "Joe",
age: 40
}).toBe({
name: "Joe",
age: 40
})
Este ejemplo utiliza toBe
. La prueba falla porque este comparador no comprueba la igualdad en profundidad: comprueba el valor, no todas las propiedades.
- Utiliza el comparador
toEqual
para comprobar la igualdad profunda:
expect({
name: "Joe",
age: 40
}).toEqual({
name: "Joe",
age: 40
})
Esta prueba se supera porque ambos objetos son «profundamente iguales», es decir, todas sus propiedades son iguales.
- Prueba otro ejemplo de comparador que comprueba si la matriz definida contiene un elemento concreto.
expect(["orange", "pear", "apple"]).toContain("mango")
Esta prueba falla porque toContain
afirma que la matriz ["orange", "pear", "apple"]
contiene un valor esperado "mango"
, pero la matriz no lo contiene.
- Utiliza variables para realizar la misma prueba que con el código siguiente:
const fruits = ["orange", "pear", "apple"];
const expectedFruit = "mango";
expect(fruits).toContain(expectedFruit)
Prueba código asíncrono
Hasta ahora, hemos probado código síncrono: expresiones que devuelven un valor antes de que el código ejecute la línea siguiente. También puedes utilizar Jest para código asíncrono con async
, await
, o Promesas.
Por ejemplo, el archivo apis.js tiene una función para realizar una solicitud de API:
function getTodos() {
return fetch('https://jsonplaceholder.typicode.com/todos/1')
}
La función getTodos
envía una solicitud GET
a https://jsonplaceholder.typicode.com/todos/1
.
- Crea un archivo llamado apis.test.js con el siguiente código para probar la API falsa:
const { getTodos } = require('./apis')
test("gets a todo object with the right properties", () = > {
return getTodos()
.then((response) = > {
return response.json()
})
.then((data) = > {
expect(data).toHaveProperty('userId')
expect(data).toHaveProperty('id')
expect(data).toHaveProperty('title')
expect(data).toHaveProperty('completed')
expect(data).toHaveProperty('description')
})
})
Este caso de prueba invoca la función getTodos
que obtiene un objeto todo
. Cuando resuelve la Promise, utiliza el método .then
para obtener el valor resuelto.
En ese valor, el código devuelve response.json()
, que es otra Promise que convierte la respuesta al formato JSON. Otro método .then
obtiene el objeto JSON que contiene los expect
y los emparejadores. El código afirma que el objeto JSON incluye cinco propiedades: userId
, id
, title
, completed
, y description
.
- Ejecuta las pruebas:
Como muestra la captura de pantalla, la prueba para getTodos()
falla. Espera la propiedad description
, pero la API no la devuelve. Con esta información, ahora puedes pedir al equipo de gestión de la API de tu empresa que incluya esa propiedad si la aplicación la necesita o actualizar las pruebas para que se ajusten a la respuesta de la API.
- Elimina la aserción para la propiedad
description
y vuelve a ejecutar las pruebas:
La captura de pantalla muestra que todo ha superado la prueba.
- Ahora prueba a utilizar
async/await
en lugar del manejo tradicional de Promise:
test("gets a todo object with the right properties", async () = > {
const response = await getTodos()
const data = await response.json()
expect(data).toHaveProperty("userId")
expect(data).toHaveProperty("id")
expect(data).toHaveProperty("title")
expect(data).toHaveProperty("completed")
})
La palabra clave async
está ahora antes de la función. El código utiliza await
antes de getTodos()
y await
antes de response.json()
.
Funciones Avanzadas de Jest
Funciones y módulos simulados
Puede que quieras probar una expresión con dependencias externas al escribir pruebas. En algunos casos, especialmente en las pruebas unitarias, tus pruebas unitarias deben estar aisladas de los efectos externos. En ese caso, puedes simular tus funciones o módulos con Jest para controlar mejor tus pruebas.
- Por ejemplo, considera un archivo functions.js que contiene el siguiente código:
function multipleCalls(count, callback) {
if (count < 0) return;
for (let counter = 1; counter <= count; counter++) {
callback()
}
}
La función multipleCalls
se ejecuta en función del valor de count
. Depende de la función de devolución de llamada: la dependencia externa. Su finalidad es saber si multipleCalls
ejecuta correctamente la dependencia externa.
- Para simular la dependencia externa y seguir el estado de la dependencia en tu archivo de prueba, functions.test.js, utiliza este código:
const { multipleCalls } = require('./functions')
test("functions are called multiple times correctly", () => {
const mockFunction = jest.fn()
multipleCalls(5, mockFunction)
expect(
mockFunction.mock.calls.length
).toBe(5)
})
Aquí, el método fn
del objeto jest
crea una función simulada. A continuación, el código ejecuta multipleCalls
pasando 5
y la función simulada como argumentos. A continuación, afirma que el mockFunction
es llamado cinco veces. La propiedad mock
contiene información sobre cómo el código llama a la función y los valores devueltos.
- Cuando ejecutes la prueba, éste será el resultado esperado:
Como se ha demostrado, el código llama al mockFunction
cinco veces.
En el código, la función simulada imita una dependencia externa. No importa cuál sea la dependencia externa cuando la aplicación utilice multipleCalls
en producción. A tu prueba unitaria no le importa cómo funciona la dependencia externa. Sólo verifica que multipleCalls
funciona como se espera.
- Para simular módulos, utiliza el método
mock
y pasa una ruta de archivo, que es el módulo:
const {
truncate,
} = require("./string-format")
jest.mock("./string-format.js")
Este código imita todas las funciones que exporta string-format.js y realiza un seguimiento de la frecuencia con que las llama. El truncate
del módulo se convierte en una función imitada, lo que hace que la función pierda su lógica original. Puedes averiguar cuántas veces se ejecuta truncate
en tus pruebas en la propiedad truncate.mock.calls.length
.
Si tienes un error o tu código no funciona, compara tu código con la implementación completa.
Prueba Componentes React con Jest y la Biblioteca de Pruebas React
Si aún no tienes un proyecto para seguir este tutorial, puedes utilizar este proyecto React de ejemplo como punto de partida. La rama starter-files
te ayudará a empezar a componer el código mientras sigues el tutorial. Utiliza la main
como referencia para cotejar tu código con el código completo de este tutorial.
Puedes utilizar Jest para probar frameworks de JavaScript como React. Cuando creas proyectos React con Create React App, éstos admiten React Testing Library y Jest de forma predeterminada. Si creas un proyecto React sin Create React App, instala Jest para probar React con Babel y React testing library. Si clonas la rama starter-app
, no necesitas instalar dependencias ni aplicar configuraciones.
- Si utilizas el proyecto de ejemplo, utiliza este comando para instalar las dependencias necesarias:
npm install --save-dev babel-jest @babel/preset-env @babel/preset-react react-testing-library
También puedes utilizar Enzyme en lugar de React Testing Library.
- Actualiza tus configuraciones de Babel en babel.config.js o crea este archivo si no existe:
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
- Considera el archivo src/SubmitButton.js que tiene el siguiente código:
import React, { useState } from 'react'
export default function SubmitButton(props) {
const {id, label, onSubmit} = props
const [isLoading, setisLoading] = useState(false)
const submit = () => {
setisLoading(true)
onSubmit()
}
return
Este componente SubmitButton
recibe tres props:
id
– El identificador del botón.label
– Qué texto mostrar en el botón.onSubmit
– Qué función activar cuando alguien pulse el botón.
El código asigna la propiedad id
al atributo data-testid
, que identifica un elemento para la prueba.
El componente también rastrea el estado isLoading
y lo actualiza a true
cuando alguien pulsa el botón.
- Crea la prueba para este componente. Coloca el siguiente código en un archivo SubmitButton.test.js:
import {fireEvent, render, screen} from "@testing-library/react"
import "@testing-library/jest-dom"
import SubmitButton from "./SubmitButton"
test("SubmitButton becomes disabled after click", () => {
const submitMock = jest.fn()
render(
<SubmitButton
id="submit-details"
label="Submit"
onSubmit={submitMock}
/ >
)
expect(screen.getByTestId("submit-details")).not.toBeDisabled()
fireEvent.submit(screen.getByTestId("submit-details"))
expect(screen.getByTestId("submit-details")).toBeDisabled()
})
El código anterior renderiza el componente SubmitButton
y utiliza el método de consulta screen.getByTestId
para obtener el nodo DOM mediante el atributo data-testid
.
El primer expect
es getByTestId("submit-details")
y utiliza el modificador not
y el comparador toBeDisabled
(expuesto desde react-testing-library
) para afirmar que el botón no está desactivado. Utiliza el modificador not
con cada emparejador para afirmar lo contrario del emparejador.
A continuación, el código dispara el evento submit
en el componente y comprueba que el botón está desactivado. Puedes encontrar más comparadores personalizados en la documentación de la biblioteca de pruebas.
- Ahora, ejecuta las pruebas. Si has clonado la rama
starter-files
, asegúrate de que tienes instaladas todas las dependencias del proyecto ejecutandonpm install
antes de iniciar las pruebas.
Ejecuta informes de cobertura del código
Jest también ofrece informes de cobertura de código para mostrar qué parte de tu proyecto estás probando.
- Pasa la opción
--coverage
a Jest. En tu script Jest en package.json (en el proyecto JavaScript), actualiza el comando Jest con esta opción de cobertura:
"scripts": {
"test": "jest --coverage"
}
- Ejecuta
npm run test
para probar tu código. Obtendrás un informe como el siguiente
Este informe muestra que Jest ha probado el 100% de las funciones de SubmitButton.js y string-format.js. También indica que Jest no ha probado ninguna declaración ni línea en string-format.js. La cobertura de las pruebas muestra que las líneas no probadas en string-format.js son 7 y 12.
En la línea 7, return str
de la función truncate
no se ejecuta porque la condición if (str.length <= count)
devuelve false
.
En la línea 12, también en la función truncate
, el return substring
no se ejecuta porque la condición if (!withEllipsis)
devuelve false.
Integra Jest con Tu Flujo de Trabajo de Desarrollo
Veamos cómo puedes integrar estas pruebas para mejorar tu flujo de trabajo de desarrollo.
Ejecuta pruebas en Watch Mode
En lugar de ejecutar manualmente las pruebas, puedes ejecutarlas automáticamente cuando cambies el código utilizando el modo Watch Mode.
- Para activar el modo vigilancia, actualiza tu script de comandos Jest en package.json (en el proyecto JavaScript) añadiendo la opción
--watchAll
:
"scripts": {
"test": "jest --coverage --watchAll"
}
- Ejecuta
npm run test
. Activa Jest en Watch Mode:
Las pruebas se ejecutan cada vez que modificas tu proyecto. Este enfoque promueve la retroalimentación continua a medida que construyes tu aplicación.
Configura Ganchos Pre-Commit
En los entornos Git, los ganchos ejecutan secuencias de comandos cada vez que se produce un evento concreto (como pull, push o commit). Los ganchos de pre-commit definen qué scripts se ejecutan para el evento de pre-commit (que el código activa antes de hacer una confirmación).
La confirmación sólo tiene éxito si el script no lanza un error.
Ejecutar Jest antes de la confirmación previa garantiza que ninguna de tus pruebas falle antes de la confirmación.
Puedes utilizar varias bibliotecas para configurar ganchos git en tu proyecto, como ghooks.
- Instala
ghooks
endevDependencies
:
npm install ghooks --save-dev
- Añade un objeto
configs
en el nivel superior de tu archivo package.json (en el proyecto JavaScript). - Añade un objeto
ghooks
debajo deconfigs
.
- Añade una propiedad con una clave de
pre-commit
y un valor dejest
.
{
…
"config": {
"ghooks": {
"pre-commit": "jest"
}
},
}
- Confirma el código. El código activa el gancho pre-commit, que ejecuta Jest:
Resumen
Ahora ya sabes cómo integrar Jest en tu flujo de trabajo de desarrollo para que se ejecute automáticamente cada vez que hagas un cambio. Este enfoque proporciona una retroalimentación continua para que puedas corregir rápidamente cualquier problema de código antes de lanzar tus cambios a producción.
Alojando tu aplicación con Kinsta, te beneficias de una infraestructura rápida y segura, desplegando tus proyectos en una infraestructura construida sobre la red Premium Tier de Google Cloud Platform y máquinas C2. Elige entre los centros de datos de 37 y una CDN habilitada para HTTP/3 con PoPs de 260+.
Mantente seguro con la tecnología de contenedores aislados, dos potentes cortafuegos y la protección DDoS avanzada de Cloudflare. Y puedes integrar aplicaciones o automatizar flujos de trabajo con la API Kinsta.
Configura Jest y explora los recursos de Kinsta hoy mismo para mejorar tus aplicaciones JavaScript.
Deja una respuesta