Probar interfaces de usuario

Esta sección describe cómo los desarrolladores probarán la base de código relacionada con la UI.

Stack de pruebas

Todas nuestras pruebas de UI DEBEN realizarse usando Jestarrow-up-right como el framework de pruebas principal con redux-saga-test-planarrow-up-right como la herramienta de pruebas para sagas y react testing libraryarrow-up-right como herramienta para probar componentes de UI. El código de las pruebas DEBE escribirse usando Typescriptarrow-up-right y ejecutarse usando ts-jestarrow-up-right para tener soporte de comprobación de tipos.

Qué probar

  • Componentes de UI

  • Sagas

  • Reducers

  • Selectors

  • Creadores de acciones

  • Funciones utilitarias

Probando sagas

Las sagas nos permiten manejar efectos secundarios creando generadores que gestionan acciones de redux. Una de las principales ventajas de las sagas es su capacidad de ser probadas, ya que los efectos que se usan ampliamente en las sagas son altamente testeables.

Estos handlers DEBEN ser probados usando redux-saga-test-planarrow-up-right, y la prueba DEBE ejercer toda la ejecución, desde el handler del módulo completo (su handler principal o sagas) a través de toda la ejecución de los handlers que reaccionarán a la acción que vamos a dispatch. Este enfoque hace que las pruebas de sagas sean fáciles de construir y mantener, y aporta valor a las pruebas al recorrer tanto como sea posible del flujo completo.

Las pruebas de los handlers DEBEN realizarse a través de su interacción con los effects, principalmente con el put uno, ya que su propósito es manejar acciones y producir nuevas. La mayoría de las pruebas seguramente contendrán un provide call, usado para mockear effects, una o múltiples put calls, para verificar que los handlers dispatchen las acciones como se espera y un único dispatch seguido por un run call para ejecutar las sagas completas hasta la finalización.

El mocking de recursos externos al módulo que se está probando DEBERÍA hacerse usando los providers de redux-saga-test-plan aprovechando los distintos effects provistos por redux-sagas. Effects como call, apply u otros DEBERÍAN usarse siempre que sea posible cuando se invoca una función en una prueba para permitir mockearlos fácilmente. Jest NO DEBERÍA usarse para mockear módulos o funciones.

El texto en el describe y sus DEBEN seguir estas pautas:

  • El describe principal de una saga o handler principal DEBE comenzar con when handling, indicando que lo que se va a probar es un handler. Tras la when handling frase, DEBE escribirse una descripción de la acción (o la intención que la acción) que se va a manejar. Ej. when handling the action that signals a successful fetch.

  • Los describes internos diferenciarán contextos de ejecución, siguen las mismas reglas descritas en la Describing and building context sección.

  • El its DEBEN describir lo que se espera de la prueba, comenzando con un should put y la descripción de las acciones que deberían ser puestas al ejecutar el handler.

Ejemplo de sagas

Ejemplo de prueba de sagas

Probando reducers

Reducers son funciones que toman un state y una action y devuelven un nuevo state. Este nuevo state PUEDE contener cambios programados para ocurrir por la acción dada.

Las pruebas DEBERÍAN variar los estados iniciales y los diferentes parámetros de la acción a probar si es necesario. Las aserciones DEBEN hacerse sobre todo el state retornado ya que una acción podría modificar cualquier parte del state inicial dado.

Al reducir una acción, DEBERÍAMOS usar el creador de acciones, haciendo que las pruebas sean más fáciles de mantener.

Para estandarizar la forma en que escribimos describes y its:

  • Los describes principales DEBERÍAN comenzar describiendo qué acciones van a ser reducidas usando la frase when reducing the action seguida de una descripción de la acción. NO DEBERÍAMOS usar el tipo de la acción para describir la acción a probar, ya que el type podría cambiar.

  • El its DEBERÍAN describir de manera clara cómo cambió el state retornado. Ej.: it should return a state with the error nulled and the fruits set.

Ejemplo de reducer

Ejemplo de prueba de Reducers

Probando selectors

Selectors son métodos que toman un state y devuelven una sección de ese state o una sección transformada del state.

Hay dos tipos de selectors, selectors memoizados y selectors normales o comunes. Los selectors normales o comunes DEBEN probarse como cualquier otra función de unidad y los selectors memoizados DEBERÍAN probarse usando el resultFunc o la función que recibe las partes memoizadas del state y devuelve el valor deseado.

Describes y its DEBEN escribirse como se describe en la Describing and building context sección.

Ejemplo de Selectors

Ejemplo de prueba de Selectors

Probando creadores de acciones

Los creadores de acciones son los encargados de crear las actions que luego serán procesadas en los reducers. Aunque los creadores de acciones suelen ser simples, DEBEN probarse para asegurar que hacen lo que esperamos.

Describes y its DEBEN escribirse como se describe en la Describing and building context sección.

Ejemplo de creadores de acciones

Ejemplo de prueba de creadores de acciones

Probando componentes de UI

Para probar componentes de UI estamos usando React Testing Libraryarrow-up-right. Estamos usando esta librería en lugar de otras opciones como enzyme ya que nos permite probar componentes teniendo en cuenta cómo el usuario interactuará con ellos en lugar de la implementación en sí. No interactuaremos con instancias de componentes de react, en su lugar interactuamos con elementos del DOM tal como se renderizan.

Qué probar

El propósito de esta prueba de componentes de UI es probar el comportamiento del componente y cómo el usuario interactúa con él. En muchos casos puede haber componentes que estén conectados al store de redux para obtener algunas propiedades y llamar a algunas acciones. Normalmente manejamos esto haciendo un archivo container separado que interactuará con el store. Estos archivos están fuera del alcance de este tipo de pruebas. Estamos probando cómo se comporta el componente con diferentes valores de props; no deberíamos preocuparnos por la fuente de esos valores (redux store, context, componente padre), sino por cómo impactan el render final.

Renderizado

Cada prueba debe comenzar llamando a la función render. Esto renderizará no solo el componente que pasamos como parámetro, sino también todos los hijos. Debemos evitar hacer esto en la configuración de la prueba (beforeEach) ya que puede causar problemas haciendo que el árbol del DOM tenga más componentes de los que queremos. Debemos guardar el resultado en una propiedad llamada screen. Hacer esto nos permitirá obtener todas las propiedades que necesitamos en la prueba sin la necesidad de cambiar constantemente la destructuración.

Si el documento tendrá múltiples pruebas y el componente tiene múltiples props podemos crear una función al principio del archivo que se encargue de establecer props por defecto y renderizar el componente.

Queries

Las Queries son los métodos que Testing Library te da para encontrar elementos en la página. Hay diferentes tipos de queriesarrow-up-right que podemos usar para acceder a los elementos. Debemos intentar siempre usar las queries que son Accessible to everyone ya que son las que reflejan la experiencia para todos los usuarios (visual/con ratón y usuarios de tecnología asistiva).

Esas queries son getByRole, getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. Si podemos acceder al elemento usando estas queries probablemente significa que el componente no es accesible.

Probando eventos de usuario

No podremos acceder a funciones dentro del componente por lo que deberíamos imitar el comportamiento del usuario que conduce a que esas funciones sean llamadas. Para ello usamos userEvent library.

Depuración

Para depurar la prueba y ver cuál es el estado actual del DOM en un momento específico podemos usar debug función que es una de las propiedades devueltas al llamar a render

Ejemplo completo de prueba de componente de UI

Estructura de directorios

Las pruebas DEBEN colocarse junto a los archivos o módulos que van a ejercitar, con el mismo nombre, pero con la extensión spec.ts en lugar de ts.

Una estructura de archivos DEBE verse así:

Última actualización