La pirámide de pruebas de front-end: cómo repensar sus pruebas

Si está probando aplicaciones de front-end, debería conocer la pirámide de prueba de front-end .

En este artículo veremos qué es la pirámide de pruebas de front-end y cómo usarla para crear conjuntos de pruebas completos.

La pirámide de pruebas de front-end

La pirámide de pruebas de front-end es una representación de cómo se debe estructurar un conjunto de pruebas de front-end.

El conjunto de pruebas ideal se compone de pruebas unitarias, algunas pruebas instantáneas y algunas pruebas de extremo a extremo (e2e).

Esta es una versión renovada de la pirámide de prueba, que es específica para probar aplicaciones de front-end.

En este artículo, veremos cómo se ve cada uno de estos tipos de prueba. Para hacer eso, crearemos un conjunto de pruebas para una aplicación de ejemplo.

La aplicación

Para conocer en detalle la pirámide de pruebas de front-end, veremos cómo probar una aplicación web.

La aplicación es una aplicación modal simple. Al hacer clic en un botón se abre un modal y al hacer clic en un botón Aceptar en el modal se cierra el modal.

Construiremos la aplicación a partir de un marco basado en componentes. No se preocupe por los detalles, vamos a mantener este alto nivel.

La aplicación se compone de tres componentes: un Buttoncomponente, un Modalcomponente y un Appcomponente.

Las primeras pruebas que escribiremos son pruebas unitarias. En la pirámide de pruebas de front-end, la mayor parte de nuestras pruebas son pruebas unitarias.

Pruebas unitarias

Pruebas unitarias unidades de prueba de una base de código.

Llaman a funciones, o unidades, directamente y se aseguran de que devuelvan el resultado correcto.

En nuestra aplicación, nuestros componentes son unidades. Así que escribiremos pruebas unitarias para Button y Modal. No es necesario escribir pruebas para nuestro Appcomponente porque no tiene lógica.

Las pruebas unitarias mostrarán componentes de renderizado superficial y afirmarán que se comportan correctamente cuando interactuamos con ellos.

El renderizado superficial significa que renderizamos el componente a un nivel de profundidad. De esta manera podemos asegurarnos de que solo estamos probando el componente, nuestra unidad y no un componente secundario varios niveles hacia abajo.

En nuestras pruebas, activaremos acciones en los componentes y comprobaremos que los componentes se comporten como se espera.

No miraremos el código. Pero las especificaciones de nuestros componentes se ven así:

  • Modal tiene la clase está activa cuando displayModal es verdadero
  • Modal no tiene clase is-active cuando displayModal es falso
  • Modal llama a toggleModal cuando se hace clic en el botón de éxito
  • Modal llama a toggleModal cuando se hace clic en el botón Eliminar
  • El botón llama a toggleModal cuando se hace clic en el botón

Nuestras pruebas harán un render superficial de los componentes y luego verificarán que cada una de las especificaciones funcione.

Hay algunas razones por las que las pruebas unitarias deberían constituir la mayor parte de nuestro conjunto de pruebas:

Las pruebas unitarias son rápidas.

Un conjunto de cientos de pruebas unitarias se ejecuta en unos pocos segundos.

Esto hace que las pruebas unitarias sean útiles para el desarrollo. Al refactorizar el código, podemos cambiar el código y ejecutar las pruebas unitarias para comprobar que los cambios no rompieron el componente. En unos segundos sabremos si rompimos algo, porque una de las pruebas fallará.

Las pruebas unitarias son granulares

En otras palabras, son muy específicos.

Si falla una prueba unitaria, la prueba rota nos dirá cómo y por qué falla.

Las pruebas unitarias son buenas para verificar los detalles finos de cómo funciona nuestra aplicación. Son la mejor herramienta para usar durante el desarrollo, especialmente si sigue el desarrollo basado en pruebas.

Pero no pueden probar todo.

Para asegurarnos de que estamos renderizando el estilo correcto, necesitamos usar pruebas de instantáneas.

Pruebas instantáneas

Las pruebas de instantánea son pruebas que toman una imagen de su componente renderizado y la comparan con una imagen anterior de su componente.

La mejor manera de escribir pruebas instantáneas en JavaScript es con Jest.

En lugar de tomar una foto del componente renderizado, Jest toma una instantánea del marcado del componente renderizado. Esto hace que las pruebas de instantáneas de Jest sean mucho más rápidas que las pruebas de instantáneas tradicionales.

Para registrar una prueba de instantánea en Jest, debe agregar algo como el siguiente código:

const renderedMarkup = renderToString(ModalComponent)expect(renderedMarkup).toMatchSnapshot()

Una vez que registra una instantánea, Jest se encarga de todo lo demás. Cada vez que se ejecutan las pruebas unitarias, regenera una instantánea y la compara con la instantánea anterior.

Si el código cambia, Jest arroja un error y advierte que el marcado ha cambiado. El desarrollador puede verificar manualmente que no se haya eliminado ninguna clase por accidente.

En la siguiente prueba, alguien ha eliminado la modal-card-footclase de la er>.

Snapshot tests are a way of checking nothing has changed about the style or markup of a component.

If the snapshot tests pass, we know our code change didn’t affect the display of our components.

If the tests fail, then we know that we did affect the render of the components and can check manually that the style is still correct.

You should have at least 1 snapshot test per component. A typical snapshot test renders the component with some state to check it renders correctly.

Now we have unit tests and snapshot tests, it’s time to look at end to end (e2e) tests.

End to end tests

End to end (e2e) tests are high-level tests.

They perform the same actions as we would if we tested an App manually.

In our app we have a user journey. When the user clicks on the button the modal will open, when they click the button in the modal the modal closes.

We can write an end to end test that runs through this journey. The test will open the browser, navigate to the webpage, and run through each action to make sure the app is behaving correctly.

These tests tell us that our units are working together correctly. It gives us high confidence that the main functionality of the app is working.

There are a few ways to write end to end tests for JavaScript applications. There are programs like test cafe that record you performing actions in a browser and replay them as tests.

There are also projects like nightwatch that let you write the tests in JavaScript. I would recommend using a library like nightwatch. It’s easy to pick up, and the tests run faster than recorded tests.

That said, nightwatch tests are still relatively slow. A suite of 200 unit tests takes seconds to run, a suite of 200 end to end tests takes minutes to run.

The other problem with end to end tests is that they are difficult to debug. When a test fails, it’s hard to find out why it failed, because the tests cover a lot of functionality.

Conclusion

To test front-end component based web apps effectively, you need to three types of tests. Unit tests, snapshot tests, and e2e tests.

You should have multiple unit tests for each component, one or two snapshot tests per component, and one or two end to end tests that test multiple components connected together.

Overall unit test will make up the bulk of your tests, you’ll have some snapshot tests, and a few e2e tests.

If you follow the front-end testing pyramid, you’ll create maintainable web apps with killer test suites.

You can see an example repository of the app with snapshot tests, unit tests, and end to end tests on GitHub.