Probando Componentes en React Usando Jest: Lo Básico
Spanish (Español) translation by Juan Bautista Nemi (you can also view the original English article)



Evaluar el código es una práctiaca confusa para muchos desarrolladores. Eso es entendible porque realizar pruebas requiere más esfuerzo, tiempo, y la capacidad de prever los casos de uso posible. Los Startups y desarrolladores que trabajan en proyectos más pequeños generalmente deciden ignorar las pruebas en conjunto debido a la falta de recursos y capital humano.
Sin embargo, hay algunas razones por las que creo que deberías probar tus componentes:
- Te hace sentir más confiado con tu código
- Las pruebas mejoran tu productividad
React no es tan diferente. Cuando toda tu aplicación empieza a verse como una pila de componentes que son difíciles de mantener, realizar evaluaciones ofrece estabilidad y consistencia. Establecer evaluaciones desde el día uno te ayudará a escribir mejores líneas de código, encontrar bugs con facilidad, y mantener un mejor flujo de desarrollo.
En este artículo, te llevaré a través de todo lo que necesitas saber para escribir las pruebas para los componentes React. También cubriré algunas de las mejores prácticas y técnicas durante el desarrollo del mismo. Comencemos!
Evaluar Componentes en React
Evaluar es el proceso de verificar que nuestras test assertions son verdaderas y que permanecen verdaderas durante la ejecución de la aplicación. Una afirmación de prueba (test assertion) es una expresión booleana que devuelve un resultado verdadero a menos que haya un error en tu código.
Por ejemplo, una afirmación podría ser algo tan simple como esto:
"Cuando el usuario navega a /login, un modal con el id #login debe ser renderizado." Entonces, si resulta que cometiste un error con el componente login de alguna manera, la afirmación devolvería un valor falso. Las afirmaciones no están limitadas sólo a lo que se renderiza—también es posible hacer afirmaciones sobre cómo la aplicación responde a las interacciones con el usuario y otras acciones.
Existen muchas estratégias de evaluación automatizadas que los desarrolladores frontend utilizan para probar su código. Vamos a limitar nuestra discusión a sólo tres paradigmas de evaluación de software populares en React: testeo por unidad, testeo funcional, y testeo de integración.
Testeo por Unidad
El Testeo por Unidad es veterano de los métodos de testeo que todavía es popular en los círculos de testeo. Como su nombre sugiere, consiste en evaluar piezas individuales de código para verificar que funcionan independientemente como se espera. Debido a la arquitectura de componentes de React, los Testeos por Unidad son adecuados. También son más rápidos ya que no requiere el uso de un buscador.
El Testeo por Unidades ayuda a ver cada componente por sí solo y tratarlos como funciones. Tus testeos por unidad para un componente en particular deben responder las siguientes preguntas:
- ¿Hay props? Si los hay, ¿qué hace con ellos?
- ¿Qué componentes renderiza?
- ¿Debería tener un estado? ¿Cuándo o cómo debería actualizar el estado?
- ¿Hay algún procedimiento que debería seguir cuando se activa o desactiva, o con interacción del usuario?
Testeo Funcional
Los Testeos Funcionales se utilizan para evaluar el comportamiento de parte de tu aplicación. Generalmente se escriben desde la perspectiva del usuario. Una pieza de funcionalidad por lo general involucra más de un componente. Puede ser un formulario completamente desarrollado o una página entera.
Por ejemplo, cuando estás haciendo un formulario de registro, puede involucrar componentes para los elementos del formulario, las alertas, y los errores si existieran. El componente renderizado después de que el formulario se envía también es parte de la funcionalidad. Esto no requiere un renderizador del buscador ya que utilizaremos un virtual DOM en la memoria para nuestras evaluaciones.
Testeo de Integración
El testeo de integración es una estratégia de testeo en donde todos los componentes individuales se evalúan como grupo. El testeo de integración intenta replicar la experiencia del usuario mediante la ejecución de pruebas en un buscador. Esto es considerablemente más lento que el testeo funcional y por unidad ya que cada prueba se debe ejecutar en un buscador en tiempo real.
En React, los testeos por unidad son más populares que los de integración porque son más fáciles de preparar y mantener. Eso es lo que cubriremos en este tutorial.
Conoce Tus Herramientas
Necesitas ciertas herramientas y dependencias para empezar a realizar testeos por unidad y funcional a tu aplicación de React. Los he descrito abajo.
Entorno de Evaluación Jest
Jest es un entorno de evaluación que no requiere configuración y, por lo tanto, es fácil de instalar. Es más conocido que entornos de evaluación como Jasmine y Mocha porque fue desarrollado por Facebook. Además, Jest es más rápido porque usa una técnica que paraliza las pruebas entre los trabajadores. Aparte de eso, cada prueba ejecuta un entorno sandbox para evitar conflictos entre dos pruebas sucesivas.
Si usas create-react-app, incluye Jest. De lo contrario, tendrás que instalar Jest y algunas otras dependencias. Puedes leer más sobre Jest en la página de documentación de Jest.
react-test-renderer
Incluso si estás usando create-react-app, necesitarás instalar este paquete para renderizar snapshots. Las pruebas de snapshot son parte de la librería de Jest. Entonces, en lugar de renderizar la Interfaz de Usuario de toda la aplicación, es posible usar el test renderer para generar una salida serializable de HTML desde el DOM virtual. Puedes instalarlo como se indica a continuación:
1 |
yarn add react-test-renderer |
ReactTestUtils y Enzyme
react-dom/test-utils consiste en algunas de las utilidades de testeo que el equipo React proporciona. Alternativamente, puedes usar el paquete Enzyme, publicado por Airbnb. Enzyme es mucho mejor que ReactTestUtils porque es más fácil de aseverar. Comenzaremos nuestras pruebas con React utils y después haremos una transición a Enzyme más adelante.
Para instalar Enzyme, ingrese el siguiente comando.
1 |
yarn add enzyme enzyme-adapter-react-16 |
Introduzca el código en src/SetupTests.js.
1 |
import { configure } from 'enzyme'; |
2 |
import Adapter from 'enzyme-adapter-react-16'; |
3 |
|
4 |
configure({ adapter: new Adapter() }); |
Hay más información sobre esto en la sección titulada Probando Componentes de la página create-react-app.
Configurando una Aplicación de Prueba y Organizando Pruebas
Prepraremos pruebas para una aplicación demo simple que muestra una vista master/detail de una lista de productos. Puedes encontrar la aplicación demo en nuestro repositorio de GitHub. La aplicación consiste en un componente contenedor conocido como ProductContainer y tres componentes presentacionales: ProductList, ProductDetails, ProductHeader.
Estructura del Directorio
1 |
. |
2 |
├── package-lock.json |
3 |
├── package.json |
4 |
├── public |
5 |
│ ├── index.html |
6 |
│ └── manifest.json |
7 |
├── src |
8 |
│ ├── components |
9 |
│ │ ├── App.js |
10 |
│ │ ├── ProductContainer.js |
11 |
│ │ ├── ProductDetails.jsx |
12 |
│ │ ├── ProductHeader.js |
13 |
│ │ ├── ProductList.jsx |
14 |
│ ├── index.js |
15 |
│ └── style.css |
Esta demo es una buena candidata para el testeo por unidad y el testeo funcional. Se puede probar cada componente por sí solo y/o probar la funcionalidad como un todo.
Una vez que hayas descargado la demo, crea un directorio con el nombre _tests_ dentro de /src/components/. Podrás almacenar todos los archivos de prueba relacionados a esta funcionalidad dentro del directorio __test__. Los testers generalmente nombran sus archivos de prueba o .spec.js o .test.js —por ejemplo, ProductHeader.test.js o ProductHeader.spec.js.
Escribiendo Pruebas Básicas en React
Crea un archivo ProductHeader.test.js si todavía no lo has hecho. Así es como nuestras pruebas se verán básicamente:
src/components/__tests__/ProductList.test.js
1 |
describe('ProductHeader', () => { |
2 |
|
3 |
it('passing test', () => { |
4 |
expect(true).toBeTruthy(); |
5 |
})
|
6 |
|
7 |
it('failing test', () => { |
8 |
expect(false).toBeTruthy(); |
9 |
})
|
10 |
})
|
El paquete de prueba empieza con un bloque describe, el cual es una función global de Jest que acepta dos parámetros. El primer parámetro es el título del paquete de prueba, y el segundo parámetro es la implementación propiamente dicha. Cada it() en un paquete de prueba corresponde a un test o un spec. Una prueba contiene una o más expectativas que evalúan el estado del código.
1 |
expects(true).toBeTruthy(); |
En Jest, una expectativa es una aseveración que devuelve o verdadero o falso. Cuando todas las aseveraciones in un spec son verdaderas, se dice que está aprobado. De lo contrario, se dice que la prueba falló.
Por ejemplo, hemos creado dos specs de prueba. El primero debería aprobar, mientras que el segundo debería fallar.
Nota: toBeTruthy() es un emparejador predefinido. En Jest, cada emparejador hace una comparación entre el valor esperado y el valor real, y luego devuelve un booleano. Hay muchos más emparejadores disponibles, y les hecharemos un vistazo en un momento.
Ejecutando el Paquete de Prueba
create-react-app ha configurado todo lo que necesitas para ejecutar el paquete de prueba. Todo lo que tienes que hacer es ingresar el siguiente comando:
1 |
yarn test
|
Deberías ver algo como esto:



Para corregir la prueba fallida, debes reemplazar el emparejador toBeTruthy() con toBeFalsy().
1 |
expects(false).toBeFalsy(); |
¡Listo!
Usando Emparejadores en Jest
Como se mencionó antes, Jest usa emparejadores para comparar valores. Puedes usarlos para chequear las igualdades, comparar dos números o textos, y verificar la verdad de expresiones. Aquí tienes una lista de los emparejadores más conocidos en Jest.
toBe();toBeNull()toBeDefined()toBeUndefined()toBeTruthy()toBeFalsy()-
toBeGreaterThan()
toBeLesserThan()toMatch()toContain()
Esta es sólo una muestra. Puedes encontrar una lista con todos los emparejadores disponibles en los docs de referencia.
Probando un Componente React
Primero, haremos un par de pruebas a el componente ProductHeader. Abre el archivo ProductHeader.js si no lo has hecho aún.
src/components/ProductHeader.js
1 |
import React, {Component} from 'react'; |
2 |
|
3 |
class ProductHeader extends Component { |
4 |
render() { |
5 |
return( |
6 |
<h2 className="title"> Product Listing Page </h2> |
7 |
);
|
8 |
}
|
9 |
};
|
10 |
export default ProductHeader; |
¿Sientes curiosidad por saber por qué usé una clase en lugar de un componente funcional? La razón es que es más difícil probar componentes funcionales con ReactTestUtils. Si todavía te sientes curioso por saber por qué, esta discusión en Stack Overflow tiene la respuesta.
Podríamos realizar una prueba con las siguientes suposiciones:
- El componente debería renderizar una etiqueta
h2. - La etiqueta
h2debería tener una clase llamadatitle.
Para renderizar un componente y rescatar nodos DOM relevantes, necesitamos ReactTestUtils. Remueve los specs simulados y añade el siguiente código:
src/components/__tests__/ProductHeader.test.js
1 |
import React from 'react'; |
2 |
import ReactTestUtils from 'react-dom/test-utils'; |
3 |
import ProductsList from '../ProductsList'; |
4 |
|
5 |
describe('ProductHeader Component', () => { |
6 |
|
7 |
it('has an h2 tag', () => { |
8 |
//Test here
|
9 |
});
|
10 |
|
11 |
it('is wrapped inside a title class', () => { |
12 |
//Test here
|
13 |
})
|
14 |
})
|
Para chequear la existencia de un nodo h2, primero necesitaremos renderizar nuestros elementos React en un nodo DOM en el documento. Puedes hacerlo con la ayuda de algunas de las APIs exportadas por ReactTestUtils. Por ejemplo, para renderizar nuestro componente <ProductHeader/>, puedes hacer algo como esto:
1 |
const component = ReactTestUtils.renderIntoDocument(<ProductHeader/>); |
Luego, puedes extraer la etiqueta h2 del componente con la ayuda de findRenderedDOMComponentWithTag('tag-name'). El mismo chequea todos los nodos "child" y busca el que concuerde con el tag-name.
Aquí está la prueba del spec completa.
1 |
it('has an h2 tag', () => { |
2 |
|
3 |
const component = ReactTestUtils.renderIntoDocument(<ProductHeader/>); |
4 |
var h2 = ReactTestUtils.findRenderedDOMComponentWithTag( |
5 |
component, 'h2' |
6 |
);
|
7 |
|
8 |
});
|
Guardala, y tu test runner debería mostrarte que la prueba ha sido aprobada. Es en cierto modo sorprendente porque no tenemos una sentencia expect() como en nuestros ejemplos previos. La mayoría de los métodos exportados por ReactTestUtils tienen expectativas preparadas en ellos. En este caso en particular, si la utilidad de prueba no logra encontrar la etiqueta h2, arrojará un error y las pruebas fallarán automáticamente.
Ahora, intenta crear el código para la siguiente prueba. Puedes usar findRenderedDOMcomponentWithClass() para chequear si hay algún nodo con la clase 'title'.
1 |
it('has a title class', () => { |
2 |
|
3 |
const component = ReactTestUtils.renderIntoDocument(<ProductHeader/>); |
4 |
var node = ReactTestUtils.findRenderedDOMComponentWithClass( |
5 |
component, 'title' |
6 |
);
|
7 |
})
|
¡Listo! Si todo sale bien, deberías ver los resultados en verde.



Conclusión
Aunque acabamos de realizar dos pruebas de specs, hemos abarcado mucho del área en el proceso. En el siguiente artículo, haremos algunas pruebas completamente desarrolladas para nuestra página de lista de productos. También reemplazaremos ReactTestUtils con Enzyme. ¿Por qué? Enzyme ofrece una interfaz de alto nivel que es muy fácil de usar y amigable. ¡Mantente al tanto de la segunda parte!
Si en este punto estás trabado o necesitas ayuda, haznos saber en los comentarios.



