Publicación: 7 months

Descubre cómo replicar la sección de creación de cuentas de Twitch con React, Jest y React Testing Library


Antes de comenzar, te preguntarás ¿por qué yo como desarrollador frontend necesitaría realizar pruebas en mis componentes? ¿Acaso las pruebas no son solo para backend? 

Resulta que como desarrolladores frontend, somos los encargados de implementar la comunicación entre la aplicación y el usuario final. Por lo tanto, debemos asegurar que esta comunicación se lleve acabo, si o si, ya que no importante que tan rápida cargue, que tan bonita sea, que tan rápido responda el backend, si no hace lo que debe hacer para el usuario, simplemente, no sirve.

Las pruebas automatizadas nos ayudan a asegurar que nuestros componentes funcionen correctamente y hagan lo que dicen hacer. De está forma, podemos asegurar que la comunicación entre el frontend y el backend se lleve de manera adecuada.

Para realizar estás pruebas existen diferentes herramientas, tales como Jest y React testing library que nos apoyan para ejecutar nuestras pruebas de forma más sencilla. En próximos publicaciones lo explicare. Por el momento, solo quiero que conozcamos los beneficios de las pruebas automatizadas sin entrar en temas muy técnicos.

Caso práctico

Lo primero que haremos será analizar el caso práctico que vamos a resolver, el análisis es un proceso que debemos ir fortaleciendo, ya que un buen análisis nos ayudará a escribir solo el código necesario y no más.

Cómo consejo, si después de analizar no te queda claro lo que vas a resolver, no comiences a escribir código, seguro tendrás que modificarlo o en el peor de los casos empezar de 0.

Teniendo claro la importancia de un buen análisis, demos inicio.

Login Twitch

A simple vista parece un formulario bastante simple, vemos varios campos nombre de usuario, password, fecha de nacimiento y teléfono o correo electrónico. Sin embargo, a veces no sucede esto y el problema es más grande. 
 
Subestimar las cosas puede traer varias consecuencias como: malas estimaciones en el sprint, stoppers para otros equipos, código con mala calidad, código sin pruebas automatizadas, etc. 
 
Dicho esto, hagamos un análisis un poco más profundo del funcionamiento.
 
Reglas de negocio login Twitch


Después de analizar a fondo el formulario, nos hemos encontrado con varias reglas de negocio.

  • El nombre de usuario no se puede repetir
  • La contraseña debe de cumplir ciertas condiciones para estar ok
  • El correo electrónico debe tener un formato de correo valido
  • Es necesario un teléfono o correo electrónico, pero no ambos
  • El botón de registrar solo se habilita una vez que los campos nombre de usuario, password, fecha de nacimiento y teléfono o correo no son validos se hayan llenado

Teniendo esto en mente, ya podríamos comenzar a escribir nuestras primeras pruebas.

Para este ejemplo vamos a utilizar create react app, pero eres libre de utilizar tu herramienta favorita.

Creamos proyecto
npx create-react-app unsaltodelinea

Instalamos react testing library
cd unsaltodelinea

npm install --save-dev @testing-library/react @testing-library/dom

Iniciamos el proyecto
npm start

Esto nos lanzará una página por defecto, por el momento no le tomemos importancia, ya al final de la publicación veremos porque lo dejamos al último.

Para empezar a escribir nuestras primeras pruebas necesitamos crear un archivo .test 
src/CreateTwitchAccount.test.js

    1: describe('CreateTwitchAccount', () => {
    2: 
    3: });

Lo que acabamos de agregar simplemente es un “bloque” que se encargará de agrupar las pruebas del componente CreateTwitchAccount.

Ahora bien, agreguemos nuestra primera prueba

    1: describe('CreateTwitchAccount', () => {
    2:   it('crear cuenta correctamente', () => { // primera prueba
    3:     
    4:   });
    5: });

Ahora bien, antes de implementar la solución definamos ¿qué es una cuenta correcta? Podemos deducir que una “cuenta correcta” es una cuenta que tiene los campos usuario, password, fecha y teléfono o correo electrónico. Dicho esto, implementemos la solución.

    1: import {fireEvent, render, screen} from "@testing-library/react";
    2: 
    3: describe('CreateTwitchAccount', () => {
    4:   it('crear cuenta correctamente', () => {
    5:     const props = {
    6:       createAccount: jest.fn(),
    7:     }
    8: 
    9:     render(
   10:       <CreateTwitchAccount {…props } />
   11:     )
   12: 
   13:     fireEvent.change(screen.getByTestId(‘username'), { target: { value: 'Gabriel' } })
   14:     fireEvent.change(screen.getByTestId('password'), { target: { value: 'Hola1234' } })
   15:     fireEvent.change(screen.getByTestId('birthdate'), { target: { value: '10-01-1990' } })
   16:     fireEvent.change(screen.getByTestId('email'), { target: { value: '[email protected]' } })
   17: 
   18:     expect(props.createAccount).toHaveBeenCalledWith({
   19:       user: "Gabriel",
   20:       password: "Hola1234",
   21:       email: "[email protected]",
   22:       birthdate: "10-01-1990"
   23:     })
   24:   });
   25: });

A simple vista puede ser complicado pero te aseguro que no es así. Expliquemos de forma general sin entrar en temas técnicos.

Línea 1. Importamos funciones auxiliares de apoyo para nuestros tests
Línea 5..7 Definimos los props que el componente necesita
Línea 9..11 Montamos el componente con sus props
Línea 13..16 Asignamos valores a los campos
Línea 18..23 Comprobamos que el prop createAccount es invocado con los parámetros correspondientes

Ejecutemos nuestra prueba y veamos que sucede

Error, CreateTwtichAccount no está definido


Y cómo era de esperarse la prueba ha fallado, el error nos dice que CreateTwitchAccount no esta definido por lo que hay que crearlo src/CreateTwitchAccount.js

    1: const CreateTwitchAccount = () => {
    2:   return null
    3: }
    4: 
    5: export default CreateTwitchAccount

Volvamos a ejecutar la prueba.

Error, elemento username no existe


Ooh no, otro error 😩 parece que no ha encontrado ningún elemento con la propiedad data-testid=“user” y esto es cierto, el componente CreateTwitchAccount que creamos esta regresando null.

Veamos a la solución.

const CreateTwitchAccount = () => {
  return(
    <form>
      <input type="text" name="username" data-testid="username" placeholder="Usuario" />
      <input type="text" name="password" data-testid="password" placeholder="Password" />
      <input type="text" name="birthdate" data-testid="birthdate" placeholder="Fecha de nacimiento" />
      <input type="text" name="email" data-testid="email" placeholder="Correo electrónico" />
    </form>
  )
}

export default CreateTwitchAccount

Ejecutemos de nuevo la prueba.

Error, función createAccount no se invoca


¡¡Noooo!! Otro error :/ ¿y ahora que sucedió? Resulta que la prueba espera que el prop createAccount se llame pero no es así. Arreglemos esto y hagamos que nuestra prueba pase de una vez por todas.

    1: import {useState} from "react";
    2: 
    3: const CreateTwitchAccount = ({ createAccount }) => {
    4:   const [values, setValues] = useState({})
    5: 
    6:   function onChange({ target }) {
    7:     values[target.name] = target.value
    8:     setValues({ ...values })
    9:   }
   10: 
   11:   function handleSubmit(event) {
   12:     event.preventDefault()
   13: 
   14:     createAccount({ ...values })
   15:   }
   16: 
   17:   return(
   18:     <form onSubmit={handleSubmit}>
   19:       <input type="text" name="username"
   20:              data-testid="username" placeholder="Usuario" onChange={onChange} />
   21:       <input type="text" name="password"
   22:              data-testid="password" placeholder="Password" onChange={onChange} />
   23:       <input type="text" name="birthdate"
   24:              data-testid="birthdate" placeholder="Fecha de nacimiento" onChange={onChange} />
   25:       <input type="text" name="email"
   26:              data-testid="email" placeholder="Correo electrónico" onChange={onChange} />
   27:       <button type="submit">Guardar</button>
   28:     </form>
   29:   )
   30: }
   31: 
   32: export default CreateTwitchAccount

Analicemos el código

Línea 4. Creamos un estado para almacenar los valores de los campos usuario, password, fecha de nacimiento y correo
Línea 6..9. Función para actualizar los valores de los campos
Línea 19..25. Campos usados por el usuario para colocar su información
Línea 11..15. Función que se ejecutara una vez que el formulario sea enviado

 Crucemos los dedos y volvamos a ejecutar nuestra prueba

Prueba éxitosa


¡Yeah!! No más errores. Oye si, pero mmm, aun no me siento convencido de que las pruebas me ayuden a desarrollar más rápido, al contrario noto que me traería más problemas porque entre más código tengamos más mantenimiento.

Totalmente de acuerdo, sin embargo, te puedo asegurar que en aplicaciones donde existen una gran cantidad de componentes y servicios alrededor de tu aplicación el beneficio de tener pruebas es mayor.