Testing React Native apps con Jest

Cuando estamos realizando aplicaciones en React Native no podemos olvidarnos de los tests, como no podía ser de otra manera. Ya explicamos como nos decantamos por React Native en Finizens y ahora hemos optado por el framework de testing recomendado por Facebook: Jest.

Este framework de testing nos permite, no solo realizar los tests unitarios a los que estamos acostumbrados, si no también realizar tests sobre snapshots de componentes. Esto es, renderizar un componente de React y mantenerlo en el tiempo para compararlo con el estado actual.

Instalación

Desde la versión 0.38 de React Native, Jest viene instalado y configurado en nuestro package.json por defecto. Si tienes una versión superior a la 0.38 puedes ir a la sección de Tests Unitarios dentro de este artículo, en caso de que no sea así o estemos migrando de una aplicación más antigua de React Native debemos instalarlo a través de Yarn o Npm, en nuestro caso usamos Yarn.

yarn add —-dev jest babel-jest

La primera dependencia es Jest en sí misma y la segunda el plugin de Jest para Babel. Con este plugin los test serán transpilados automáticamente usando Babel sin tener que añadir más configuración extra, lo que nos permitirá usar funcionalidades de última generación de javascript en los tests (es2015, …). En nuestro package.json después tendremos que tener una estructura como esta:

{
    // …
    “scripts”: {
        // …
        “test”: “jest”
    },
    “devDependencies”: {
        “babel-jest”: “20.0.3”,
        “babel-preset-es2015”: “6.24.1”,
        “babel-preset-react-native”: “1.9.2”,
        “jest”: “20.0.4”
    },
    “jest”: {
        “preset”: “react-native”
    }
}

Los paquetes de presets de react-native y es2015 deben venir instalados por defecto independientemente de la versión de React Native usada.

Test unitarios

Vamos a comenzar usando Jest para los tests más básicos de nuestra aplicación, donde vamos a probar individualmente las librerías y lógica que usaremos, en lugar de usar el típico ejemplo de suma de números que está en todos los tutoriales vamos a ir con un ejemplo real aunque muy sencillito.

Para ponernos en contexto, en nuestra aplicación hay contenida una webview, pero no permitimos abrir cualquier URL, para limitarlo tenemos una lista blanca de dominios los cuales podemos abrir desde nuestra aplicación, para comprobar si un dominio está en esta lista tenemos una función que usamos como servicio. La localización de este servicio es src/services/external-link-validator.js, por lo que vamos a crear nuestro test en __tests__/services/externa-link-validator.test.js, la carpeta __tests__ en la raíz es donde Jest busca los tests por defecto.

En nuestro test vamos a especificar las aserciones que queremos que cumpla nuestro validador de urls.

Estamos definiendo el comportamiento que tendrá validateExternalLink, tiene que validar el dominio del enlace, tanto con protocolo o sin él y también con o sin path. Ya teniendo un test podemos ejecutarlo y ver como falla estrepitosamente, ya que no tenemos este servicio definido. Para ejecutar los test usamos uno de los scripts definidos en nuestro package.json en la clave “scripts”, en este caso el script “test” lo teníamos asociado a la ejecución de “jest”:

npm run test

Teniendo los test con la funcionalidad que queremos probar, ya podemos ir realizando la implementación del servicio, en este caso para ver como los test se ejecutan vamos a añadir una implementación dummy.

export function validateExternalLink(url) {
    return true;
}

Ahora la ejecución de los test no fallará porque no encuentra el módulo a importar sino porque alguno de los test están fallando.

Ahora podemos completar la implementación para cubrir la funcionalidad, para este ejemplo haremos algo rápido separando la URL según las barras separadoras.

¡Yeah! ¡Ya tenemos nuestra batería de test corriendo y funcionando!

Test de regresión con capturas de componentes

Una característica destacable de Jest respecto a otros frameworks de testing es la posibilidad de realizar tests de regresión sobre los componentes. Estos tests toman como base un estado conocido de un componente renderizado y lo comparan contra el estado actual. En caso de detectar algún cambio marcan el test como fallido.

Con estos tests se intenta asegurar que cambios en nuestro código no tengan efectos colaterales no deseados y garantizar que el sistema tiene el mismo estado tras unos cambios que no requiriesen cambio en el estado de los componentes.

Para renderizar nuestros componentes usaremos react-test-renderer que nos permite renderizar un componente y obtener su representación en json.

yarn add --dev react-test-renderer

A continuación vamos a crear nuestro primer test que renderize un componente, en nuestro caso vamos a usar un componente sencillo para la didáctica y renderizaremos el elemento de “Cargando…”.

En este test renderizamos el componente <Loading />, obtenemos su representación en json y lo comparamos con un snapshot. Al no haber ejecutado el test nunca, en la primera ejecución de los test se creará el archivo de snapshot y el test pasará.

En la misma carpeta donde esté el test se habrá creado un directorio __snapshots__ donde estará la representación de este componente. En la próxima ejecución de los test si se comparará el resultado actual contra el anterior.

Snapshots: 1 passed, 1 total

En caso de que cambiemos el componente el test fallará, en este caso vamos a cambiar levemente una propiedad en el componente Loading para ver el resultado del test

Si este es el resultado que queremos que tenga nuestro componente de ahora en adelante debemos regenerar los snapshots para que tome el estado actual como el correcto.

Este comando actualiza todos los snapshots, importante ejecutar los test antes y ver que fallan solo los componentes deseados.
node node_modules/jest/bin/jest.js --updateSnapshot

Para no tener que recordar el comando anterior de actualizar los snapshots, podemos añadirlo como un script más de npm en nuestro package.json.

{
    “scripts”: {
        // …
        “jest-update-snapshot”: “jest --updateSnapshot”
    },
    // …
}

E invocarlo con:

npm run jest-update-snapshot

Esto actualizará los snapshots y la siguiente ejecución de los test será satisfactoria con el nuevo estado del componente.

Conclusión

Esto es algo realmente fácil de configurar y aporta un gran valor al proyecto, con estos sencillos pasos y configuración podemos tener una base para ejecutar nuestros test unitarios y de regresión, especialmente con estos últimos conseguiremos darnos cuentas de efectos colaterales al modificar los componentes de nuestra aplicación.