Pruebas automatizadas de extremo a extremos (e2e)
Contenidos
¿Qué son?
Estas son pruebas que se aplican simulando la interacción de un usuario real ejecutando una historia de usuario
Aprendizajes esperados
Utilizar herramientas basadas en NoseJS para automatizar pruebas de UI. Saber utilizar la documentación de Cypress para escribir buenas pruebas e2e (end-to-end). Aplicar técnicas de pruebas ágiles para desarrollar productos de software de alta calidad.
Instalación del proyecto
- npm install
- npm run serve
Probar http://localhost:4000
¿Qué es Cypress?
Cypress es un framework de pruebas simple, rápido y confiable para automatizar pruebas de UI, las más altas en la pirámide del test para cualquier aplicación que corra en el navegador. Sus principales ventajas son:
- Corre en un navegador real, a diferencia de los headless browser de herramientas como Selenium.
- Puede acceder al network para controlar las respuestas a sus solicitudes.
- Los elementos a interactuar deben ser visibles, no que solo estén presentes en el html.
- Print de pantallas y videos
- Sólido proyecto open source
¿Quién lo usa?
https://www.cypress.io/case-studies
¿Qué es lo que hace?
Cypress permite automatizar la experiencia de un usuario interactuando con un sitio web de manera de utilizar los conceptos de Pruebas de software para corroborar que los objetivos del sitio o aplicación se cumplen.
Cypress tiene la capacidad de viajar y debuggear cada paso de las pruebas como lo veremos en acción. Cypress es síncrono y no requiere que se programen temporizadores para esperar la respuesta de la aplicación. Además puede sacar videos y print de pantallas de toda la suit de tests o de los casos fallidos. Además permite configurar dobles de prueba y establecer el horario de la aplicación.
Instalación
npm install cypress --save-dev
Analicemos un poco que hace Cypress al instalarse:
👀 https://docs.cypress.io/guides/getting-started/installing-cypress#Installing 👀
Vamos a crear los siguientes scripts:
"test": "cypress open",
"test:ci": "cypress run"
Ahora ejecutamos:
npm test
En windows debemos permitir Cypress en el firewall
Cypress nos guiará a través de un proceso de instalación donde nos explicará qué archivos creará en nuestro directorio de proyecto. Luego de seleccionar el Navegador Web donde queremos correr las pruebas, veremos una pantalla como la siguiente donde Cypress nos pedirá elegir si crear archivos de prueba por nosotros o elegimos crear una prueba desde cero:
Seleccionaremos la opción Create new empty spec
y luego tendremos la opción de darle un nombre a la primera prueba. La llamaremos cypress/e2e/website.cy.js
como muestra la siguiente imagen:
Luego nos mostrará el código de la prueba creada y elegiremos la opción para ejecutarla. Veremos algo como lo siguiente:
Pruebas para un Sitio Web
Luego de la prueba exitosa que viene en la instalación, comenzaremos a editarla para que tenga sentido con el sitio web que tenemos actualmente.
Vamos al archivo cypress/e2e/website.cy.js
y cambiaremos la instrucción que dice cy.visit
y modificaremos todo el archivo que quedará finalmente de esta forma:
describe('empty spec', () => {
it('passes', () => {
cy.visit('http://localhost:4000')
})
})
Es evidente que la prueba ahora este fallando. Esto es porque no hemos levantando nuestro sitio web en el puerto 4000. Para ello, sin cerrar la ventana de la terminal que está corriendo Cypress, abriremos una nueva y correremos la instrucción npm run serve
.
Veremos que una vez más la prueba este pasando.
Sigamos modificando la prueba, esta vez para que valide el encabezado principal de la página. Para esto experimentaremos usando la función cy.get() que podemos revisar en la documentación de Cypress
El código ahora debería verse de la siguiente manera:
it('should show the right title', () => {
cy.visit('http://localhost:4000')
cy.get('.hero-section h1').should('include.text', 'Programadores más influyentes de la historia')
})
Listo! tenemos nuestra primera prueba automatizada al sitio web.
Ejercicio: Automatizar historias de usuario: BDD y TDD
En simple, Behavior Driven Development or Design es Test Driven Development bien hecho.
Objetivo
Validar automáticamente los campos requeridos del formulario. Al presionar el botón “comentar” deberían validarse los campos y agregar el error “Este campo es obligatorio”.
👀 Instrucciones 👀
Con la herramienta Cucumber convertiremos un requerimiento en formato de historia de usuario a pruebas automatizadas de UI, para asegurar que la comunicación entre módulos tienen supuestos correctos y se comunican correctamente con la interfaz. Esto involucrará integrar librerías de terceros para resolver los requerimientos funcionales implícitos. Seguiremos el ciclo TDD red-green-refactor.
Vamos a integrar la librería Pristine utilizando la metodología Test Driven Development (TDD).
Utilizando Gerkhin a través de un Plugin para Cypress
Ahora utilizaremos Cucumber para hacer más expresivas las pruebas de Software y permitir que otros roles relacionados a la construcción de productos digitales compartan sus impresiones al momento de definir un requerimiento. Utilizaremos esta tecnología de “Automatización” para escribir pruebas como por ejemplo:
Feature: Write comments in a page form
The user can write comments in page
Scenario: Send form without required fields
Given the user is in the homepage
When the button "comentar" is pressed without the required fields
Then those fields should show the message "Este campo es obligatorio"
Instalación y configuración
Primero vamos a detener Cypress. Y ahora instalaremos 2 nuevos paquetes:
npm i -D @badeball/cypress-cucumber-preprocessor @cypress/browserify-preprocessor
El primero es el preprocesador de Gherkin, que mapea líneas de las historias de usuario a pasos que Cypress debe ejecutar. El segundo paquete es un bundler utilizado internamente por el preprocesador.
(Browserify)[https://browserify.org/] permite utilizar la función require
en el Navegador parseando el Árbol de sintaxis
Vamos a editar el archivo cypress.config.js
:
const { defineConfig } = require("cypress");
const preprocessor = require("@badeball/cypress-cucumber-preprocessor");
const browserify = require("@badeball/cypress-cucumber-preprocessor/browserify");
async function setupNodeEvents(on, config) {
await preprocessor.addCucumberPreprocessorPlugin(on, config);
on("file:preprocessor", browserify.default(config));
// Make sure to return the config object as it might have been modified by the plugin.
return config;
}
module.exports = defineConfig({
e2e: {
specPattern: "**/*.feature",
setupNodeEvents,
},
});
Escribir archivo .feature
Vamos a crear un archivo llamado website.feature
en la ruta indicada en el siguiente trozo de texto:
cypress/e2e/website.feature
Feature: Write comments in a page form
The user can write comments in the page so
Scenario: Send form without required fields
Given the user is in the homepage
When the button "comentar" is pressed without the required fields
Then those fields should show the message "Este campo es obligatorio"
Ejecutamos npm test
y vemos que sucede.
También podemos probar npm run test:ci
y revisar la carpeta videos.
Escribir step definitions
Ahora vamos a migrar las pruebas ya escritas a la nueva forma de escribir pruebas. Para esto vamos a editar el archivo cypress/e2e/website.cy.js
. y cambiarle el nombre a cypress/e2e/website.js
Acá escribiremos el siguiente código:
const { Given } = require("@badeball/cypress-cucumber-preprocessor");
const url = 'http://localhost:4000'
Given('the user is in the homepage', () => {
cy.visit(url)
})
Escribir más step definitions
Ahora sumaremos otros pasos que permitan encontrar los elementos con los atributos data-cy
que corresponde. Aún las pruebas fallarán, pero al menos ya tenemos seleccionados los elementos de la ui que deben implementar la funcionalidad.
Iremos agregando estos y veremos como las pruebas siguen fallando, pero ya no informan la ausencia de estos atributos. Si quiere entender porque utilizamos esta notación, te recomendamos el siguiente artículo
const { Given, When, Then } = require("@badeball/cypress-cucumber-preprocessor");
const url = 'http://localhost:4000'
Given('the user is in the homepage', () => {
cy.visit(url)
})
When('the button "comentar" is pressed without the required fields',() => {
cy.get('form button[type="submit"]').click()
})
Then('those fields should show the message "Este campo es obligatorio"',() => {
cy.get('[data-cy="email"] .pristine-error')
.should('include.text', 'Este campo es requerido')
cy.get('form .form-group:nth-child(2) .pristine-error')
.should('include.text', 'Este campo es requerido')
})
Resolver la funcionalidad
Agregamos Pristine desde un CDN
https://cdn.jsdelivr.net/npm/pristinejs@0.1.9/dist/pristine.min.js
y haremos esto agregando un script al archivo website/index.html
en la sección script al final del archivo.
Vamos a agregar el siguiente código:
const form = document.querySelector("form")
// create the pristine instance
const pristine = new Pristine(form);
form.addEventListener('submit', (e)=> {
e.preventDefault();
// check if the form is valid
const valid = pristine.validate(); // returns true or false
});
Aún no esta completo. Ahora debemos revisar la documentación de Pristine acá
y agregaremos lo siguiente a los elementos <input>
que corresponda
data-pristine-required-message="Este campo es requerido"
Integración continua
Si intentamos correr el comando npm run test:ci
veremos problemas con correr las pruebas en un solo proceso.
Para esto utilizaremos el paquete “start-server-and-test”
npm i -D start-server-and-test
modificamos la sección scripts en el package.json
:
...
"scripts": {
"serve": "http-server -p 4000 website",
"test": "cypress open",
"cypress:run": "cypress run",
"test:ci": "start-server-and-test serve http-get://127.0.0.1:4000 cypress:run"
},
...
y finalmente correr npm run test:ci
.
Más detalle revisa la documentación oficial de Cypress respecto a Integración Continua
No soportados
Cypress puede automatizar eficientemente muchas de las pruebas de UI, pero carece de funcionalidades que podría tener si fuera una herramienta de propósito general. Debemos entender que Cypress no está pensado para hacer web scraping o pruebas de estrés. Hay otras herramientas para esos propósitos. Cypress no soporta pruebas en múltiples pestañas dentro del navegador y solo podemos hacer pruebas en un solo domino de origen. Tampoco podemos probar multiples instancias del navegador. Cómo Cypress corre solo en el navegador, se requiere trabajo adicional si queremos hacer cosas fuera del navegador, además cada cy.visit
debe ir en su propio test.
it("visit multiple sites", ()=>{
cy.visit("https://boolean.cl")
cy.visit("https://jsconf.cl") // throws an erro
})
Puedes revisar las alternativas para entender las funcionalidades no soportadas y las que vienen en camino como cy.hover()
y cy.tab()
Ejercicio 2: incorporando Network requests
Vamos a escribir pruebas para más casos analizando el directorio 2-advanced-examples
revisando el archivo relacionado a “Network requests” generando un flujo definido incluyendo una petición al servidor que pudiera o no existir.
¡Éxito!