Jest + Enzyme — Una gentil introducción

Carlos Alfredo Olivera Venegas
Crehana
Published in
6 min readApr 25, 2018

Empezare diciendo que soy nuevo en los tests y que este sera un resumen sobre lo que he leído recientemente sobre testing aplicado a React js; Si, esa librería que por estos días todos conocemos y se ha vuelto tan famosa 👌

Antes de empezar a ver propiamente que librerías usar para testear nuestros componentes, he buscado información sobre What should I test? (Por cierto, utilizare alguna expresiones en ingles durante el post porque configure el teclado en ingles y no tengo “ñ” así como otros signos como interrogación, me siento cómodo así y de pasada que practico algunas expresiones del english que debemos siempre recordar de vez en cuando, por no decir siempre 😅 ).

Como decia, WHAT SHOULD I TEST?.

Fue lo primero que busque ya que a diferencia del código en backend donde tienes lógica de negocio que pensar si bien es cierto hay mas complejidad pero al final sueles tener siempre menos code que testear a diferencia de la cantidad interminable de componentes visuales que puedes tener en la interfaz de tu app, estamos hablando aquí de hacer testing a componentes visuales, en React JS los conocidos presentational componentes o esos componentes que has declarado con arrow function y su nuevo fancy style 😛 y sino lo has hecho te recomiendo que revises 45% Faster React Functional Components, Now 😱 ya que es muy importante.

En nuestras nuestras app hechas con react tendremos dos tipos de código que testear principalmente: El código de interfaz visual que ya mencione y también flujo de data e interacciones que serian tests aplicados a Redux o a la library que tengas implementada para manejar el state de tu app (Este tipo de tests los veremos mas adelante).

Antes de empezar a testear tenemos que conocer el “contract” de nuestro componente, es termino que significa “contrato” hace referencia a la forma en la funciona nuestro componente, debemos entender como funciona nuestro componente: What it renders? Props? Conditional renders? entre otras cosas.

Una de las cosas mas importantes que debes recordar es NO evitar un test porque sea demasiado complicado o tedioso de hacer, es justamente esas partes las que son mas criticas.

No te saltes tests dificiles, siempre son importantes 😫

SI testear:

  • Interfaz publica (Un ejemplo seria cuando nuestro component pudiera recibir un prop que genere un render condicional, habría que testear si dado un prop A se renderiza un componente A y dado un prop B se renderiza un componente B).
  • Que las funciones que llaman los eventos clicks funcionen.
  • Cualquier otra parte del componente que consideres importante.

NO es necesario testear:

  • PropTypes, ya que la libreria ‘prop-types’ se encarga perfectamente de ello.
  • Estilos inline, a menos que sea dinámicos.
  • No testear cosas que no le conciernen a tu componente especifico, recuerda que estos tests son unitario y probar las relaciones entre diferentes tests seria parte de otro tipo de test (Test de integración).

Configuracion de Jest + Enzyme

Primero debemos instalarlo. Utilizare yarn en vez de npm. Recuerda utilizar el adapter para tu version de react, la mía es 15, por eso uso enzyme-adaptar-react-15, mas info aquí.

yarn add jest enzyme enzyme-adapter-react-15

Mi archivo de configuración se llama test-setup.js y lo coloco en la raíz de mi proyecto. Aquí configuraremos el adaptar y unas cosas adicionales.

Para que jest pueda configurarse con ese archivo hay que especificarlo en el package.json

{
"name": "crehana",
"jest": {
"setupTestFrameworkScriptFile": "<rootDir>/test-setup.js"
}
}

Nomenclatura y estructura de los test

Utilizo comunmente dos tipos de tests: unitarios y de integracion.

Tests unitarios

Estos tests son para probar la funcionalidad de codigo especifico dentro de un componente por lo que lo pongo al mismo nivel del componente a testear.

Tests de integracion

Estos sirven para testear la integración entre dos o mas componentes, así que crearemos una carpeta llamada tests para organizarlos.

|- /src
| |- index.js
| |- index.unit.test.js <== Test unitario
|- /tests
| |- /int
| | |- api.int.test.js <== Test integracion

Preparando los tests

Veamos ahora un ejemplo de como funciona Jest + Enzyme y las maravillas que nos prometen 🐶

Veamos dos funciones de Enzyme que usaremos constantemente y sus diferencias: mount y shallow ⛳️

El siguiente componente

const ButtonWithIcon = ({icon, children}) => (
<button><Icon icon={icon} />{children}</button>
);

Con mount:

<button>
<i class="icon icon_coffee"></i>
Hello Jest!
</button>

Con shallow:

<button>
<Icon icon="coffee" />
Hello Jest!
</button>

La diferencia es que mount renderiza un componente como normalmente react lo haria, en cambio shallow solo renderiza el primer nivel del componente.

En algunos casos no necesitaremos renderizar el componente entero para testearlo pero en otros si, debemos identificarlos ya que la opción “mount” tardara mas que “shallow”, si hay uno cosa que al final termina haciendo pesadilla los tests son cuando estos pasan de tardar unos segundos a muchos minutos 😖.

Bueno, regresemos a nuestro componente, visualmente el componente se ve así:

ChatView.jsx and ChatMessage.jsx

Para la mayoría de tests utilizare esta plantilla:

Luego veremos porque nos es util este boilerplate 👍

Ahora veamos nuestro componente a testear ChatView,

El componente ChatView renderiza una lista de ChatMessage dependiendo del prop messages que pasemos, para esto prepararemos un test unitario así:

|- /src
| |- ChatView.jsx
| |- ChatView.unit.test.js <== Test unitario

Agregaremos a los props de la plantilla anterior los “messages” para poder simular el renderizado y tmb agregaremos al final el código para testearlo.

chatView() nos referencia a un wrapper de Enzyme del componente que le dimos, en este caso <ChatView />. Este wrapper nos da acceso a través de métodos como find para buscar al igual que lo haríamos cuando en aquel entonces se usaba jQuery.

Como al componente le pasamos un array con dos objetos, esperamos que el render contenga 2 componentes ChatMessage, con .find encontramos los ChatMessage y con length nos devuelve la cantidad, finalmente usamos toBe que es similar a hacer una comparación con “==”.

JEST describe y JEST test

Los tests se agrupan en bloques que definimos con “describe”, y los tests se definen con “test”.

Ahora testearemos eventos dentro del componente como por ejemplo los clicks. Vamos a probar que cuando hacemos click en el button enviar se ejecute la function addMessage que le pasamos por props. Agregamos lo siguiente:

En la linea 5 podriamos haber usado jest.fn() en vez de sinon.spy() pero escogi sinon porque nos da otro tipo de opciones adicionales y como los tests no afectan el performance de la pagina preferi agregarlo desde ahora para tener mas opciones con esta libreria 🐕.

Veras que casi siempre utilizamos enzyme dentro de expect para hacer selecciones del render y probar que existen o que cumplen con cierta regla y seguido del expect va el método comparativo que como ves es en este toBeTruthy() , estos son los llamados matchers de JEST.

Basicamente para testear rapido deberas conocer una cierta cantidad de matchers para hacer tus comparaciones y por otro lado saber manejar el api de enzyme para poder simular clicks, buscar elementos, modificar el state, obtener el state, obtener props y toda una lista de cosas que nos permite hacer Enzyme, pero continuemos con los ejemplos 👌

Ahora probaremos que el state se esta seteando como esperamos

Y ya esta.

Recuerda siempre hacer fallar tus tests antes que hacerlos pasar, hay muchos casos de falsos positivos dentro de la comunidad, por lo que por todos lados dirán que debemos hacer fallar el test y luego poco a poco ir haciendo que pasen, y debemos escuchar esos sabios consejos 🙌

Dejo el archivo de test completo de este componente:

Por cierto, al final intente simular un evento focus pero nose pudo. Si alguien fuera tan amable de comentar con la solucion, estare demasiado agradecido y sere feliz.

“A pineapple on the beach with tidewwater.” by Evi Radauscher on Unsplash

Gracias.

--

--