En este post aprenderás a escribir tu primer test con Cypress, con solo un index.html verás que el testing es bello, sencillo y sumamente valioso dentro de tus proyectos. 💖
Cypress es un framework de testing que nos permite hacer pruebas End to End (E2E), que corren en el navegador y cuyo objetivo es replicar al máximo el comportamiento real de un usuario dentro de nuestra aplicación.
Cypress ya incluye librerías de aserciones, mocks y además tiene features muy interesantes como Screenshots y Videos de los test, intercepción de las peticiones http y otras tantas cosas que hacen que escribir test sea sencillo y rápido.
Para tener una aplicación que testear, vamos a crear un ejemplo sencillo solo con un index.html
, cuyo única función será ingresar nuestro nombre y luego saludarnos.
Creemos la estructura básica que suele crearse automáticamente tecleando html:5
y después vamos a añadir nuestros inputs:
<div class="box"> <input type="text" class="input is-primary is-large" placeholder="Introduce tu nombre" id="name-input" /> <button class="button is-primary is-large is-fullwidth" id="name-btn">Saludame</button> </div>
También le pondremos un poco de CSS porque somos frontends.
body { font-family: system-ui; display: flex; justify-content: center; align-items: center; flex-direction: column; height: 100vh; } button { margin-top: 16px; border: 1px solid transparent; border-radius: 4px; box-shadow: none; height: 2.5em; line-height: 1.5; background-color: #00d1b2; border-color: transparent; font-size: 1.5rem; color: #fff; width: 100%; outline: none; } input { border: 1px solid #00d1b2; line-height: 1.5rem; font-size: 1.5rem; box-shadow: inset 0 0.0625em 0.125em rgb(10 10 10 / 5%); color: #363636; height: 2.5em; padding-bottom: calc(.5em - 1px); padding-left: calc(.75em - 1px); padding-right: calc(.75em - 1px); padding-top: calc(.5em - 1px); outline: none; max-width: 100%; width: 100%; box-sizing: border-box; border-radius: 4px; } input:focus { box-shadow: 0 0 0 0.125em rgb(0 209 178 / 25%); } input::placeholder { color: #b3b3b3; } button:hover { background-color: #00c4a7; } button:active { background-color: #00b89c; } .box { background-color: #fff; border-radius: 6px; box-shadow: 0 0.5em 1em -0.125em rgb(10 10 10 / 10%), 0 0 0 1px rgb(10 10 10 / 2%); color: #4a4a4a; display: block; padding: 1.25rem; }
Para tener un servidor de desarrollo, abriremos nuestro index.html utilizando la extensión de Live Server.
Ahora solo falta agregar un poco de JS para que cuando clickemos 'Saludame' apareza un mensaje de 'Bienvenido a Cypress ${tu nombre}'. :3
<script> const input = document.querySelector('#name-input') const button = document.querySelector('#name-btn') button.addEventListener('click', () => { const name = document.createElement('h1') name.innerHTML = `Bienvenido a Cypress, ${input.value}` name.classList.add('box') name.id = 'greeting' document.body.appendChild(name) }) </script>
Ya tenemos una aplicación sencilla, pero funcional, asi que vamos a instalar Cypress llendo a la terminal, inicializando un nuevo proyecto con yarn init
o npm init
e ingresando el comando.
yarn add cypress
Ten paciencia, puede tardar un poco, sobre todo si es la primera vez que usas Cypress en tu computador.
Una vez que añadimos Cypress a nuestro pequeño proyecto, se nos crean un par de carpetas dentro del mismo:
Cada una de ellas tiene un propósito y es el siguiente:
Fixtures: Aquí puedes guardar tus mocks que son la mejor manera de simular datos de respuesta para tu aplicación.
Integration: Todos los test que escribas van dentro de esta carpeta, vienen algunos ejemplos por default, los archivos llevaran el nombre en el formato nombre.spec.js.
Plugins: Aquí podemos darle poderes adicionales a Cypress para hacer cosas como agregar un Dark Mode o un tema a la interfaz de Cypress, añadir comandos y selectores más complejos, añadirle soporte a cosas como el Drag and Drop, etc.
Support : Si deseas crear comandos personalizados que hagan tareas repetitivas como el login y que estos estén disponibles en todos tus archivos de test, aqui debes colocarlos.
cypress.json: Contiene las configuraciones base de tu aplicación como el hostname o baseUrl, si deseas guardar screenshots de los errores o tomar video de toda tu ejecución, etc.
A continuación necesitamos añadir a nuestro package.json los scripts que usaremos para correr Cypress en modo de desarrollo y desde la consola:
"scripts": { "test:open": "cypress open", "test:run": "cypress run" }
Tambien agregaremos un poco de configuracion dentro de cypress.json:
{ // La direccion de donde esta corriendo nuestra aplicación "baseUrl": "http://localhost:5500", // EL tamaño del viewport que deseamos tener "viewportWidth": 1366, "viewportHeight": 768, "chromeWebSecurity": false }
Y finalmente correremos el comando que abre la interfaz grafica de Cypress:
yarn test:open
¡Listo! Ya tienes Cypress corriendo en tu navegador.
Vamos a crear un archivo hello.spec.js dentro de nuestra carpeta integration donde vamos a escribir los test de nuestra aplicación, recuerda abrirlo en la interfaz así conforme avancemos y vayas guardando tus cambios, Cypress los tomara y los correrá.
La estructura básica de un test es la siguiente:
describe('Nombre de mi test', () => { // Grupo de aserciones que debe de cumplirse // para que el test sea considerado exitoso it('Nombre de la aserción', () => { // Comandos que describen el estado deseado // de mis elementos y mi aplicación }) })
Siempre es recomendable detenerse a pensar un momento que queremos testear y cuáles son los pasos a realizar para verificar que esté funcionando correctamente. En nuestro caso para saber que nuestra aplicación nos está saludando correctamente necesitamos:
Teniendo esto en cuenta comencemos con nuestra estructura básica:
describe('La app me saluda correctamente', () => { it('Puedo visitar el sitio', () => { }) it('El estado incial de mi app es el correcto', () => { }) it('La app me saluda', () => { }) })
Listo, ahora vamos a escribir los comandos necesarios para verificar que estas aserciones son correctas.
Lo primero es entrar a nuestro sitio y para eso tenemos el comando visit que se usa de la siguiente manera:
cy.visit('http://localhost:3000') // Va a la baseUrl configurada en cypress.json cy.visit('/') // Va por el archivo local "index.html" cy.visit('index.html')
Ahora vamos a aplicarlo a nuestros test:
describe('La app me saluda correctamente', () => { it('Puedo visitar el sitio', () => { // Esto se rompera si nuestro server esta apagado o // si hay un error 404 o similar cy.visit('/') }) // ... }
¡Listo! Ya has creado tu primer test exitoso.
Continuemos avanzando, ahora vamos a aprender a seleccionar un elemento del DOM usando Cypress utilizando el comando get que recibe por parámetros un selector que puede ser de clase, de ID, de atributo, de etiqueta o combinaciones entre estos:
// Selecciona todos los elementos de tipo input cy.get('input') // Selecciona los elementos con la clase .btn cy.get('.btn') // Selecciona el elemento con id #form cy.get('#form') // Selecciona el elemento que incluye la palabra 'blog' en su atributo href cy.get('a[href*="blog"]') // Selecciona el primer li dentro del elemento con la clase .menu cy.get('.menu li:first') // Selecciona el elemento con el atributo data-cy igual a price // Esta es una muy buena practica por que las clases y los id's pueden cambiar, este es un atributo solo para cypress cy.get('[data-cy=submit]') // Si hay multiples elementos con el mismo selector puedes ir por el primero o el ultimo cy.get('.item').first() cy.get('.item').last() // Existen muchos mas selectores interesantes
Una vez seleccionado nuestro elemento, podemos comenzar a realizar aserciones utilizando el comando should que recibe por parámetros cualquier descripción basada en asesiones de chai.
Veamos un poco de ejemplos, este concepto es sumamente intuitivo y autodescriptivo.
// El elemento nav debe ser visible cy .get('nav') .should('be.visible') // El elemento btn-sumary debe estar deshabilidado cy .get('#btn-submit') .should('be.disabled') // El formulario debe tener la clase form subscription cy .get('form') .should('have.class', 'form-subscription') // El contador debe tener un valor de 3 cy .get('counter') .should('have.value', 3)
Las posibilidades del should son infinitas, te recomiendo que revises la documentación a fondo, vamos a realizar las aserciones sobre el estado inicial de nuestra aplicación. Si deseas ver el HTML y el JS que generamos, vuelve arriba.
describe('La app me saluda correctamente', () => { // ... it('El estado incial de mi app es el correcto', () => { // Mis inputs se esta renderizando y es visible cy.get('#name-input') .should('be.visible') // Mis botton existe y es visible cy.get('#name-btn') .should('be.visible') // Mi saludo no deberia existir cy.get('#greeting') .should('not.exist') }) // ... })
Ya sabemos como seleccionar elementos del DOM y como hacer aseciones sobre ellos, ahora solo nos faltan dos comandos mas: type y click para poder ejecutar la mismas acciones que el usuario.
Para usar .type()
solo necesitas pasarle como parametro el string que sera ingresado y lucira asi:
Y click(), solo lo ejecutas despues de seleccionar un elemento en el DOM y listo, agregemoslos a nuestro ulitmo test :3
describe('La app me saluda correctamente', () => { ... it('La app me saluda', () => { cy.get('#name-input') .type('miguelseguramx') cy.get('#name-btn') .click() cy.get('#greeting') .should('have.text', 'Bienvenido a Cypress, miguelseguramx') }) })
¡Listo! Lo has conseguido, has replicado el comportamiento de un humano con software y te has asegurado que un flujo va a correr exitosamente.
Una vez que esten exitosos puedes cerrar las ventanas de cypress y correr los test desde la terminal con yarn test:run
Ahora que ya conoces lo basico de Cypress, te invito a que continues revisando la documentacion y experimentes con nuestra aplicación para añadir nuevas funcionalidades y test. Si deseas puedes hacer la propia y conectarla a una API, incluso eres bienvenido a escribir la segunda parte de este blog si asi lo deseas.
Cuentame que te parecio el post y sobre que te gustaria que hablara en mis redes sociales o en Discord.
¡Se valiente y No te rIndas!