El entorno de pruebas

Como se introdujo en Qué son las pruebas, las pruebas en JavaScript son, básicamente, código que confirmamos que se ejecuta de forma correcta, es decir, sin arrojar una Error. Sin embargo, una de las formas en que esta definición es una simplificación excesiva es que no considera dónde se ejecuta el código, es decir, su entorno de pruebas.

En términos generales, el entorno de pruebas puede considerarse como dos componentes: el entorno de ejecución que usas para ejecutar la prueba (como Node o el navegador) y las APIs disponibles.

El entorno de ejecución

Los entornos de ejecución, como Node, o herramientas similares, como Deno o Bun, tienen como objetivo admitir código JS de uso general o del servidor. Sus entornos no incluyen las APIs que podrías esperar en un navegador, como crear y trabajar con los elementos DOM y HTML, ni ningún concepto de componente visual o destino de renderización (es decir, no solo elementos, sino que se renderizan visualmente con CSS en un viewport).

Por lo tanto, estos tiempos de ejecución de uso general fallarán si intentas, por ejemplo, renderizar elementos de React para que se puedan probar, ya que no hay objetos document o window disponibles.

Por otro lado, si ejecutas las pruebas en un navegador, es posible que las APIs integradas que esperas en estos entornos de ejecución no estén disponibles sin polyfills o trabajo adicional. Un problema común es leer y escribir archivos: no es posible usar import { fs } from 'node:'fs'; en un navegador y leer un archivo de esta manera como parte de una prueba.

Este problema de la API de “web” versus “backend” está un poco fuera del alcance de las pruebas, ya que puede ser incómodo tener una base de código con las partes del servidor y el cliente, pero se relaciona con la idea de escribir código que se puede probar, que revisaremos en este curso.

Probar la lógica empresarial o algorítmica

Parte de tu código no requerirá importaciones de Node ni del navegador para funcionar y, por lo tanto, realizar pruebas. Veremos esto más adelante en el curso, pero estructurar la base de código de modo que su “lógica empresarial” pura sea independiente de la renderización o el código específico de nodo puede facilitar las pruebas.

Para ver un ejemplo rápido, puedes tener una función de Node que lee y escribe un archivo desde el disco, y lo modifica en el proceso. Cuando refactorizas tu función para aceptar funciones que realizan la lectura y escritura desde el disco, puedes hacer que se pueda probar en cualquier lugar.

En este caso, puedes usar cualquier entorno para probar este código, ya sea en el entorno de ejecución del servidor o en el navegador. En la prueba, puedes proporcionar asistentes que almacenen un archivo virtual en la memoria o muestren datos del marcador de posición. Se puede introducir este tipo de asistente en una prueba, ya que no es importante verificar, por ejemplo, que fs.writeFileSync funcione. Enfócate en el código y en qué lo hace único o riesgoso.

Emula las APIs del navegador

Muchos frameworks de prueba, como Vitest, te presentan la opción de emular el entorno de API del navegador sin ejecutar un navegador. Vitest usa internamente una biblioteca llamada JSDOM. Esta puede ser una buena opción para pruebas de componentes simples en las que la sobrecarga de usar un navegador es alta.

Una característica común de las bibliotecas de emulación es que, aunque pueden emular un navegador (por ejemplo, el DOM, los elementos y las cookies), no tienen un componente visual. Esto significa que proporcionarán una manera imperativa de trabajar con elementos HTML y otras primitivas, pero no podrás renderizar el resultado en una imagen o pantalla, ni verificar la posición de un elemento en píxeles en la página.

Nuevamente, esta opción puede ser adecuada para las pruebas de componentes, en las que un componente representa un elemento de React, un componente web, etcétera. Por lo general, estos tipos de componentes crean el DOM e interactúan con él de una manera relativamente pequeña, y un navegador emulado puede proporcionar suficiente funcionalidad para confirmar que el componente funciona como deseas. En una próxima sección, se incluye un ejemplo de una prueba de componentes de React con Vitest y JSDOM.

La emulación de un navegador es una práctica consolidada (JSDOM en 2014), pero siempre diferirá del uso de un navegador real. Estas diferencias pueden ser obvias: por ejemplo, JSDOM no incluye un motor de diseño, por lo que no hay forma de verificar el tamaño de un elemento ni probar un gesto complejo, como deslizar el dedo. Las diferencias también pueden ser sutiles y desconocidas, por lo que es mejor que las pruebas basadas en JSDOM sean concisas, de modo que puedas “bloquear el tiempo” del riesgo de que cualquier comportamiento se desvíe del elemento real.

Controla un navegador real

Para probar tu código a medida que los usuarios lo experimentarán, la mejor opción es usar un navegador real. En la práctica, los entornos de ejecución de prueba que admiten el navegador iniciarán y controlarán las instancias de un navegador real, incluso si ejecutan “start” dentro de Node.js.

Si controlas un navegador como parte de una prueba, este se abrirá tal como lo haría un usuario, lo que permitirá que la prueba lo controle cargando URLs, HTML y JS personalizados, o lo que sea necesario para realizar la prueba. Luego, puedes escribir código para que actúe como un usuario; por ejemplo, puedes controlar el mouse o escribir una entrada en los cuadros de entrada.

Las herramientas modernas como WebdriverIO o Web Test Runner pueden controlar todos los navegadores principales y hasta ejecutar varias instancias al mismo tiempo. Estos navegadores pueden ejecutarse junto al ejecutor de pruebas (por ejemplo, en tu propia computadora o como parte de una acción de CI) o se pueden subcontratar a servicios comerciales externos que los ejecutarán por ti.

Las bibliotecas de prueba más establecidas (incluidas Vitest y Jest) a menudo tienen un modo de navegador, pero como su origen es de Node.js, sus modos de navegador a menudo están "agregados" y les faltan funciones útiles. Por ejemplo, Vitest no puede simular importaciones de módulos en el navegador, que es una primitiva potente que usamos en el ejemplo de la página siguiente.

En la práctica

A medida que aumenta la complejidad de las pruebas, se vuelve cada vez más importante usar un navegador real.

  • Para las pruebas que usan funciones mínimas o nulas del DOM, incluso las funciones que están disponibles en Node.js y entornos de ejecución similares, como fetch o EventTarget, el entorno no importa.
  • Para pruebas de componentes pequeños, JSDOM puede ser adecuado.
  • Las pruebas más grandes, por ejemplo, las pruebas de extremo a extremo, que pueden simular que un usuario accede y realiza una acción principal, tienen sentido para ejecutarse por completo en un navegador real.

Esta sección incluye mucha teoría y presenta diferentes puntos de vista sobre dónde ejecutar las pruebas. En la práctica, tu base de código a menudo usará muchos enfoques diferentes para distintos tipos de pruebas según tus necesidades y lo que proporcionan las herramientas de prueba.

Verifica tus conocimientos

¿Qué funciones del navegador *no* admite la capa de emulación jsdom?

El motor de diseño
Dado que JSDOM no es una herramienta visual, no se puede usar para comprobar la posición de un elemento en la página, sus atributos CSS resueltos ni ninguna otra parte del diseño de un sitio web.
WebSocket
JSDOM incluye el polyfill de WebSocket, por lo que el código que lo use funcionará.
requestAnimationFrame
Con el parámetro `pretendToBeVisual`, jsdom invocará la devolución de llamada 'animation' a 60 FPS, aunque en realidad no se haya dibujado nada.