Testing en React

Ing. José Miguel Amaya Camacho

miguel.amaya99@gmail.com

José Miguel Amaya Camacho

  • Ing. Informático
  • Python/Django Remote Developer
  • CTO y Cofundador de XPRENDE TECH
  • Full Stack Developer Efilm Online SL - España
  • Activista del Software Libre
  • Fundador de Python Piura

¿Qué es React?

  • React es una biblioteca de JavaScript.

  • No es un framework.

  • Es un proyecto Open Source creado por Facebook.

  • Se usa para construir interfaces de usuario (UI) en el front-end.

  • React es la capa de vista de una aplicación MVC (Model View Controller)

Características

  • Uno de los aspectos más importantes de React es el hecho de que puede crear componentes, que son elementos HTML personalizados y reutilizables, para construir interfaces de usuario de manera rápida y eficiente.
  • React también optimiza la forma en que se almacenan y manejan los datos, utilizando state y props.

Instalación

  • Static HTML File
  • Create React App:
    • npx create-react-app react-tutorial

Componentes

  • Casi todo en React consta de componentes, que pueden ser componentes de clase o componentes simples.

  • La mayoría de las aplicaciones React tienen muchos componentes pequeños, y todo se carga en el componente principal de la aplicación.

  • Los componentes también suelen tener su propio archivo, así que cambiemos nuestro proyecto para hacerlo.

React Testing Library

  • Basado en DOM Testing Library, es una solución muy liviana para probar componentes de React.

  • Proporciona funciones de utilidad ligera además de react-dom y react-dom/test-utils.

  • En lugar de tratar con instancias de componentes React renderizados, las pruebas funcionarán con nodos DOM reales.

  • Las utilidades que proporciona facilitan la consulta del DOM de la misma manera que lo haría el usuario.

¿Qué nos permite?

  • Encontrar elementos de formulario por su texto de etiqueta.

  • Encontrar enlaces y botones a partir de su texto.

  • También expone una forma recomendada de encontrar elementos por un data-testid para elementos donde el contenido del texto y la etiqueta no tienen sentido o no son prácticos.

No es

  • Un test runner o framework.

  • Específico para un framework de pruebas (se recomienda Jest pero funciona con cualquier otro).

render

  • Renderizar en un contenedor que se adjunta a document.body.

import {render} from '@testing-library/react'

test('renders a message', () => {
  const {asFragment, getByText} = render(<Greeting />)
  expect(getByText('Hello, world!')).toBeInTheDocument()
  expect(asFragment()).toMatchInlineSnapshot(`
    <h1>Hello, World!</h1>
  `)
})

Opciones para render

  • A menudo no se necesitarán, pero en caso sea necesario, estas son las opciones disponibles:

    • container

    • baseElement

    • hydrate

    • legacyRoot

    • wrapper

    • queries

Resultados para render

  • El método render devuelve un objeto que tiene algunas propiedades:

    • queries

    • container

    • baseElement

    • debug

    • rerender

    • unmount

    • asFragment

queries

  • Las queries de DOM Testing Library se devuelven automáticamente con su primer argumento vinculado a baseElement, que por defecto es document.body.

const {getByLabelText, queryAllByTestId} = render(<Component />)
  • Pero por lo general, se usa screen para acceder a las queries.

container

  • El nodo DOM container del React Element renderizado. es un div.

  • Este es un nodo DOM normal, por lo que se puede llamar a container.querySelector para inspeccionar los elementos secundarios.

  • Pero debemos evitar usar "containers" para consultar elementos.

baseElement

  • Es el nodo DOM contenedor donde el React Element está renderizado. Si no se especifica el baseElement en las opciones, se establecerá de forma predeterminada en document.body.

  • Esto es útil cuando el componente que desea probar representa algo fuera del div del contenedor: cuando desee realizar una prueba instantánea del componente de su portal que representa su HTML directamente en el cuerpo.

debug

  • Este método es un atajo para :

    • console.log(prettyDOM(baseElement)).

  • Pero se recomienda usar screen.debug en su lugar.

import React from 'react'
import {render} from '@testing-library/react'

const HelloWorld = () => <h1>Hello World</h1>
const {debug} = render(<HelloWorld />)
debug()

rerender

  • Esta función se usa para actualizar las propiedades del componente renderizado.

import {render} from '@testing-library/react'

const {rerender} = render(<NumberDisplay number={1} />)

// re-render the same component with different props
rerender(<NumberDisplay number={2} />)

unmount

  • Esto hará que el componente renderizado se desmonte.

  • Es útil para probar lo que sucede cuando su componente se elimina de la página.

  • Es una abstracción bastante pequeña sobre ReactDOM.unmountComponentAtNode

import {render} from '@testing-library/react'

const {container, unmount} = render(<Login />)
unmount()

asFragment

  • Retorna un DocumentFragment del componente renderizado. Es útil si se necesita ver cómo reacciona el componente a los eventos.

import React, {useState} from 'react'
import {render, fireEvent} from '@testing-library/react'

const TestComponent = () => {
  const [count, setCounter] = useState(0)
  return (
    <button onClick={() => setCounter(count => count + 1)}>
      Click to increase: {count}
    </button>
  )
}

const {getByText, asFragment} = render(<TestComponent />)
const firstRender = asFragment()
fireEvent.click(getByText(/Click to increase/))
expect(firstRender).toMatchDiffSnapshot(asFragment())

cleanup

  • Desmonta los árboles React que se montaron con render.

  • Esto se hace automáticamente si el test framework usado es compatible con afterEach global y se inyecta en su entorno de prueba (como mocha, Jest y Jasmine). De lo contrario, se deben realizar limpiezas manuales después de cada prueba.

    .

act

  • Es un wrapper ligero alrededor de la función act de react-dom/test-utils.

  • Todo lo que hace es reenviar todos los argumentos a la función act si su versión de react admite act.

  • Se recomienda usar la importación de @testing-library/react sobre react-dom/test-utils por razones de consistencia.

renderHook

  • Es un wrapper alrededor de render con un componente de prueba personalizado.

  • Pero se debe usar render, ya que un componente de prueba personalizado da como resultado pruebas más legibles y sólidas, ya que lo que desea probar no está oculto detrás de una abstracción..

import {renderHook} from '@testing-library/react'

test('returns logged in user', () => {
  const {result} = renderHook(() => useLoggedInUser())
  expect(result.current).toEqual({name: 'Alice'})
})

Queries

  • Sirven para encontrar elementos en la página.

  • Hay varios tipos de consultas ("get", "find", "query"); la diferencia entre ellos es si la consulta arrojará un error si no se encuentra ningún elemento o si devolverá una Promesa y volverá a intentarlo.

  • Según el contenido de la página que se esté seleccionando, diferentes consultas pueden ser más o menos apropiadas.

Tipos de Queries

  • Elementos individuales

    • getBy...

    • queryBy...

    • findBy...

  • Elementos múltiples

    • getAllBy...

    • queryAllBy...

    • findAllBy...

Elementos individuales

  • getBy...: Devuelve el nodo coincidente para una consulta y genera un error descriptivo si ningún elemento coincide o si se encuentra más de una coincidencia (use getAllBy en su lugar si se espera más de un elemento).

  • queryBy...: Devuelve el nodo coincidente para una consulta y devuelve nulo si ningún elemento coincide. Esto es útil para afirmar un elemento que no está presente. Lanza un error si se encuentra más de una coincidencia (use queryAllBy en su lugar si está bien).

Elementos individuales

  • findBy...: Devuelve una Promesa que se resuelve cuando se encuentra un elemento que coincide con la consulta dada. La promesa se rechaza si no se encuentra ningún elemento o si se encuentra más de un elemento después de un tiempo de espera predeterminado de 1000 ms. Si necesita encontrar más de un elemento, use findAllBy..

Elementos múltiples

  • getAllBy...: Devuelve una matriz de todos los nodos coincidentes para una consulta y arroja un error si no coincide ningún elemento.

  • queryAllBy...: Devuelve una matriz de todos los nodos coincidentes para una consulta y devuelve una matriz vacía ([]) si ningún elemento coincide.

  • findAllBy...: Devuelve una promesa que se resuelve en una matriz de elementos cuando se encuentran elementos que coinciden con la consulta dada. La promesa se rechaza si no se encuentran elementos después de un tiempo de espera predeterminado de 1000 ms.

Prioridades en las Queries

  • Las pruebas debe parecerse a como los usuarios interactúan con la app. Por lo que es recomendable este orden de prioridad:

    • Consultas accesibles para todos: reflejan la experiencia de usuarios visuales/ratón, así como de aquellos que usan tecnología de asistencia.

    • Consultas semánticas: Selectores compatibles con HTML5 y ARIA. La experiencia del usuario al interactuar con estos atributos varía mucho entre los navegadores y la tecnología de asistencia.

    • Test IDs

Consultas accesibles para todos

  • getByRole: consulta cada elemento que está expuesto en el árbol de accesibilidad. Con la opción name puede filtrar los elementos devueltos por su nombre accesible. Deberiamos usarlo para casi todo, si no se puede, es posible que nuestra interfaz de usuario sea inaccesible. La mayoría de las veces, se usará con la opción de nombre así:
    • getByRole('button', {name: /submit/i})

Consultas accesibles para todos

  • getByLabelText: sirve para los campos de formulario. Emula el comportamiento del usuario al navegar a través de un formulario web, ya que los elementos se ubican utilizando el texto de la etiqueta.
  • getByPlaceholderText: un marcador de posición no sustituye a una etiqueta.
  • getByText: fuera de los formularios, el contenido de texto es la forma principal en que los usuarios encuentran elementos. Se utiliza para encontrar elementos no interactivos (divs, spans y párrafos).

Consultas accesibles para todos

  • getByDisplayValue: el valor actual de un elemento de formulario puede ser útil al navegar por una página con valores completados.

Consultas semánticas

  • getByAltText: si su elemento admite texto alternativo (img, área, entrada y cualquier elemento personalizado), puede usar esto para encontrar ese elemento.
    getByTitle: los lectores de pantalla no leen el atributo de título de forma constante y no es visible de forma predeterminada para los usuarios videntes

MUCHAS GRACIAS

Preguntas

Aprendiendo React

By Miguel Amaya Camacho

Aprendiendo React

Aprendiendo a usar React

  • 141