Guía completa para configurar y realizar testing en una aplicación de React.
Introducción
El testing
es una parte fundamental en el desarrollo de aplicaciones en React.js
y en la construcción de componentes. Los tests
son esenciales para garantizar la calidad, confiabilidad y mantenibilidad de nuestras aplicaciones en React y los componentes que construimos. Nos ayudan a identificar y corregir errores, mejorar el código y brindar una base sólida para el desarrollo y la colaboración en equipo.
Beneficios de realizar pruebas en nuestras aplicaciones
- Confianza en el código: Los
tests
nos brindan confianza al asegurar que nuestro código funcione como se espera. Nos permiten validar el comportamiento de nuestros componentes y asegurarnos de que sigan funcionando correctamente incluso después de cambios o actualizaciones. - Identificación de errores: Los
tests
nos ayudan a detectar errores ybugs
en nuestras aplicaciones y componentes de manera temprana. Al escribir pruebas exhaustivas, podemos identificar y corregir problemas antes de que lleguen aproducción
, lo que nos ahorra tiempo y evita posibles problemas para los usuarios. - Mantenimiento del código: Los
tests
actúan como una línea de defensa alrefactorizar
o modificar el código existente. Al tener pruebas en su lugar, podemos realizar cambios con mayorseguridad
, ya que las pruebas nos alertarán si algo se ha roto durante el proceso de refactorización. - Facilita la colaboración: Los
tests
proporcionan un medio paracolaborar eficientemente
en el desarrollo de software. Al compartir pruebas, los miembros del equipo pueden entender rápidamente el comportamiento esperado y pueden realizar cambios o mejoras sin temor a romper la funcionalidad existente.
Instalaciones y configuraciones necesarias
Iniciar un proyecto de React con Vite
Para empezar, es necesario tener una aplicación de React
. Puedes crear una fácilmente utilizando el siguiente comando
en tu terminal:
npm create vite
Se te pedirá que ingreses un nombre
para tu proyecto y luego elijas el framework/biblioteca
que deseas utilizar. En este caso, seleccionaremos React
. También se te preguntará si deseas utilizar TypeScript
o simplemente JavaScript
. En este artículo, vamos a configurar un proyecto de React con JavaScript
. Una vez hecho esto, debes navegar hacia la carpeta del proyecto y ejecutar el siguiente comando para instalar las dependencias necesarias:
npm install
Instalar vitest, @testing-library/react y jsdom
Para realizar testing
en aplicaciones de React
, es necesario instalar las siguientes bibliotecas como dependencias en nuestro proyecto: vitest
, testing-library/react
y jsdom
. Estas bibliotecas combinadas ofrecen un conjunto de herramientas poderosas para llevar a cabo pruebas efectivas en nuestras aplicaciones React.
- Vitest: Es una biblioteca de pruebas unitarias para JavaScript. Proporciona un conjunto de utilidades y funciones que permiten escribir pruebas concisas y efectivas para el código JavaScript
- Testing-Library/React: Esta biblioteca se centra en las pruebas de componentes React. Proporciona una serie de utilidades para interactuar con componentes React y realizar aserciones sobre su comportamiento y apariencia.
- JSDOM: Es una biblioteca que simula un entorno DOM (Document Object Model) en Node.js. Permite ejecutar y probar código JavaScript que interactúa con el DOM sin necesidad de un navegador real. JSDOM proporciona una API que imita la API del DOM en el navegador
Todas estas dependencias
son de desarrollo
, lo que significa que no son necesarias para que nuestro proyecto se ejecute correctamente. Por lo tanto, al instalarlas, debemos utilizar el siguiente comando junto con la "bandera" -D
para indicar que son dependencias de desarrollo:
npm install -D vitest testing-library/react jsdom
Configurar jsdom
Cuando creamos un proyecto de React con Vite, se genera automáticamente un archivo llamado vite.config.js
donde se encuentran todas las configuraciones de Vite
. En este archivo, debemos agregar una nueva propiedad para indicar que se debe utilizar la biblioteca JSDOM
cuando se realicen las pruebas. Por lo tanto, el archivo vite.config.js
debería tener la siguiente estructura:
vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
environment: "jsdom",
globals: true,
},
});
Agregamos la propiedad test
, que contiene un objeto con las propiedades environment
y globals
. De esta manera, indicamos que se debe utilizar el entorno de jsdom
y habilitar las variables globales
en las pruebas, como window
o document
.
Agregar script en package.json para ejecutar los tests
Para configurar la ejecución de todos los tests
en nuestro proyecto, es necesario agregar un script
en el archivo package.json
. En la sección de scripts
, podemos añadir la propiedad "test"
con el valor "vitest"
de la siguiente manera:
package.json
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "vitest" // nuevo script
},
Al incluir esta configuración, podemos ejecutar todos los tests de nuestro proyecto utilizando el comando npm run test
en la terminal. Esto disparará la ejecución de los tests y mostrará los resultados correspondientes.
Al utilizar npm run test
, se ejecutará la herramienta Vitest
y comenzará a ejecutar todos los tests
disponibles en el proyecto. Esto proporciona una forma sencilla y conveniente de realizar pruebas automatizadas y verificar la integridad de nuestro código.
Configuraciones y explicaciones de Vitest
Componente al cual le haremos testing
En este artículo, vamos a realizar pruebas en un componente de tipo "acordeón". Un acordeón
es un componente
común en el que se muestra un subtítulo y, al hacer clic en él, se revela el contenido oculto. Al hacer clic nuevamente, se vuelve a ocultar el contenido.
Durante el testing
, nos aseguraremos de verificar el comportamiento esperado del acordeón, es decir, que se muestre el contenido oculto al hacer clic en el subtítulo y que se oculte nuevamente al hacer clic una vez más.
Accordion.jsx
import { useState } from "react";
//* icons *//
import { ArrowDown, ArrowUp } from "./icons";
//* styles *//
import Styles from "./Accordion.module.css";
export const Accordion = ({ children, title }) => {
const [open, setOpen] = useState(false);
return (
<article
role="accordion"
onClick={() => setOpen((prevValue) => !prevValue)}
className={Styles.accordion__card}
>
<div className={Styles.accordion__header}>
<h3 className={Styles.accordion__title}>{title}</h3>
{open ? <ArrowUp /> : <ArrowDown />}
</div>
{open ? (
<div role="content" className={Styles.accordion__content}>
<div className={Styles.accordion__more}>{children}</div>
</div>
) : null}
</article>
);
};
Este componente recibe dos propiedades: children
y title
. La propiedad children representa el contenido oculto del acordeón, mientras que title representa el subtítulo del acordeón. Además, dentro del componente, se utiliza un estado controlado por el hook useState
para indicar si el acordeón está abierto o cerrado. Este estado cambia cuando se hace clic en el acordeón.
Además, se asigna el atributo role
a la etiqueta article
y a la etiqueta div
que envuelve la propiedad children. Cada uno de ellos tiene un valor diferente. Al utilizar el atributo role
en los elementos, facilitamos la identificación y selección específica de los elementos durante el testing
.
Convención de nombres para los archivos de testing
Los archivos de testing, deben seguir una convención de nomenclatura
similar al nombre del componente al que hacen referencia. En este caso, se debe anteponer el sufijo .test
al nombre del componente y luego mantener la extensión de archivo correspondiente. Por lo tanto, el archivo de pruebas para Accordion.jsx
se llamaría Accordion.test.jsx
.
├─ 📁 accordion
| ├─ 🖇️ Accordion.jsx
| ├─ 🖇️ Accordion.test.jsx
Importaciones necesarias para realizar nuestros tests
El archivo de prueba comienza importando las funciones necesarias para los tests, como beforeEach
, describe
, expect
y test
, de la biblioteca Vitest
. También se importan las funciones fireEvent
, render
y screen
de la biblioteca Testing-Library/React
.
Accordion.test.jsx
import { beforeEach, describe, expect, test } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
Función describe de Vitest
Todos los tests
estarán contenidos dentro de una función llamada describe
. Esta función se utiliza para agrupar y organizar los tests relacionados en bloques. Proporciona un contexto y una descripción para los tests que se encuentran dentro de él. La función describe
recibe dos argumentos: un string
que se utiliza para describir las pruebas que se encuentran dentro de él y una función
que contendrá todos los tests.
Accordion.test.jsx
import { beforeEach, describe, expect, test } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
describe("Testing sobre el componente Accordion.jsx", () => {
// Todos los tests van aquí
});
Función beforeEach y render de Vitest
Antes de cada test, se utiliza la función beforeEach
en combinación con la función render
de Vitest
para realizar configuraciones previas y renderizar el componente con valores predefinidos. En este caso, se establece la propiedad title
con el valor "Más información"
y se incluye un párrafo (<p>)
dentro del componente, representando así la propiedad children
del componente. Para todo ello, primero debemos importar el componente Accordion
al archivo de test.
Esta configuración previa nos permite establecer un estado inicial
común para todos los tests, evitando la duplicación de código y simplificando el proceso de escritura de los tests.
Accordion.test.jsx
import { beforeEach, describe, expect, test } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { Accordion } from "./Accordion";
describe("Testing sobre el componente Accordion.jsx", () => {
beforeEach(() => {
render(
<Accordion title="Más información">
<p>
Duis velit pariatur labore reprehenderit velit nisi nostrud laboris
proident eu veniam sit in.
</p>
</Accordion>
);
});
});
Función test de Vitest
La función test
se utiliza para definir tests individuales dentro de un bloque describe
y verificar el comportamiento esperado de un componente o una funcionalidad específica. Dentro de la función test
, se puede escribir código para simular interacciones o eventos, invocar funciones y realizar comprobaciones utilizando las funciones de aserción proporcionadas por Vitest
, como expect
.
La función test
recibe dos argumentos: una string
que describe el test y una función
que contiene la lógica de la prueba.
Accordion.test.jsx
import { beforeEach, describe, expect, test } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { Accordion } from "./Accordion";
describe("Testing sobre el componente Accordion.jsx", () => {
beforeEach(() => {
render(
<Accordion title="Más información">
<p>
Duis velit pariatur labore reprehenderit velit nisi nostrud laboris
proident eu veniam sit in.
</p>
</Accordion>
);
});
test("Descripción acerca del test que se ejecuta aquí", () => {
// Logíca del test
});
});
Ejemplos de pruebas usando Vitest
Test: Mostrar el título todo el tiempo
El primer test
se enfoca en verificar si el título del componente Accordion.jsx
se muestra correctamente en todo momento. Para esto, se utiliza la función expect
junto con la función getByText
de la biblioteca @testing-library/react
para buscar el texto "Más información" en la interfaz.
En este test
, se utiliza la función expect
para realizar una afirmación sobre el resultado esperado. La función screen.getByText
se encarga de seleccionar el elemento que contiene el texto específico, en este caso, "Más información", dentro del componente Accordion que ha sido renderizado previo al test en la función beforeEach
. Luego, se utiliza la función toBeDefined
para verificar que el elemento existe, confirmando así que el título se muestra correctamente.
Accordion.test.jsx
describe("Testing sobre el componente Accordion.jsx", () => {
beforeEach(() => {
render(
<Accordion title="Más información">
<p>
Duis velit pariatur labore reprehenderit velit nisi nostrud laboris
proident eu veniam sit in.
</p>
</Accordion>
);
});
test("Debe mostrar el título todo el tiempo.", () => {
expect(screen.getByText("Más información")).toBeDefined();
});
});
Test: Mostrar el contenido cuando el acordeón es cliqueado
Este test
se encarga de verificar si el contenido del acordeón se muestra correctamente cuando se realiza un clic
en él. Para lograr esto, se utilizan las funciones fireEvent.click
, screen.getByRole
y screen.queryByRole
.
En el test
, se obtiene una referencia al acordeón utilizando screen.getByRole
y el atributo "accordion". A continuación, se dispara un evento de clic en el acordeón utilizando fireEvent.click(accordion)
. Después, se busca el contenido del acordeón utilizando screen.queryByRole
y el atributo "content". Por último, se utiliza la función expect
junto con toBeTruthy
para verificar si el contenido del acordeón existe y es visible en la interfaz.
Accordion.test.jsx
describe("Testing sobre el componente Accordion.jsx", () => {
beforeEach(() => {
render(
<Accordion title="Más información">
<p>
Duis velit pariatur labore reprehenderit velit nisi nostrud laboris
proident eu veniam sit in.
</p>
</Accordion>
);
});
test("Debe mostrar el contenido cuando el acordeón es cliqueado", () => {
const accordion = screen.getByRole("accordion");
fireEvent.click(accordion);
const accordionContent = screen.queryByRole("content");
expect(accordionContent).toBeTruthy();
});
});
Test: Ocultar contenido al hacer clic en el acordeón previamente clicado
Tiene como objetivo verificar si el contenido del acordeón se oculta correctamente cuando se hace clic
en el acordeón después de haber sido previamente clicado. Este test utiliza las funciones fireEvent.click
, screen.getByRole
y screen.queryByRole
.
En este test
, se obtiene una referencia al acordeón utilizando screen.getByRole
y el atributo "accordion". Luego, se simulan dos clics
consecutivos en el acordeón utilizando fireEvent.click(accordion)
. Después de los clics, se busca el contenido del acordeón utilizando screen.queryByRole
y el atributo "content". Por último, se utiliza la función expect
junto con toBeNull
para verificar si el contenido del acordeón no está presente en la interfaz.
Accordion.test.jsx
describe("Testing sobre el componente Accordion.jsx", () => {
beforeEach(() => {
render(
<Accordion title="Más información">
<p>
Duis velit pariatur labore reprehenderit velit nisi nostrud laboris
proident eu veniam sit in.
</p>
</Accordion>
);
});
test("Debe ocultar el contenido cuando se haga clic en el acordeón cuando este ya ha sido cliqueado previamente", () => {
const accordion = screen.getByRole("accordion");
fireEvent.click(accordion);
fireEvent.click(accordion);
const accordionContent = screen.queryByRole("content");
expect(accordionContent).toBeNull();
});
});
Conclusión
El testing
es una práctica fundamental en el desarrollo de aplicaciones en React.js
. Proporciona una manera de garantizar la calidad, confiabilidad y mantenibilidad de nuestras aplicaciones y componentes. A través de las pruebas, podemos identificar
y corregir errores
, mejorar el código y brindar una base sólida para el desarrollo y la colaboración en equipo.
En este artículo, hemos explorado cómo configurar
y realizar pruebas efectivas en una aplicación de React utilizando Vitest
y Testing Library
. Aprendimos cómo instalar y configurar las dependencias necesarias, cómo realizar pruebas sobre un componente de React
y cómo utilizar las funciones y herramientas proporcionadas por Vitest
y Testing Library
para simular interacciones, invocar funciones y realizar comprobaciones.
Es importante destacar que este artículo solo raspa la superficie
del mundo del testing en React
. Hay muchas más técnicas
y estrategias
avanzadas que se pueden explorar para lograr una cobertura de pruebas más completa y eficaz. Recomiendo encarecidamente seguir aprendiendo y explorando más sobre el tema, ya que el testing
es una habilidad valiosa y altamente demandada en el desarrollo de software.