Testing E2E con Cypress – Tutorial – 1ª Parte

¿Qué es un End-to-End Testing?

Antes de comenzar a explicar que es el end-to-end testing vamos a aprovechar la evolución del proyecto que se esta haciendo en el curso de VueJS, para realizar un end-to-end testing y así tener un curso práctico de testing en un proyecto que funcione.

El repositorio de github es este https://github.com/kimagure44/curso-Vue-con-proyecto

Comenzaremos definiendo ciertos conceptos y así entender mejor que es un test end to end.

El Testing es un proceso que se usa para identificara errores en nuestro código y de esta forma tener un producto lo mas estable posible.

Según la Pirámide de testing, existen varios niveles:

  • Unit Test: Comprobar los elementos fundamentales del software como objetos, funciones, eventos, etc.
  • Component Tests:  Comprobar los errores en componentes que incluyen varias funciones o elementos internos.
  • Integration Tests: Comprobar el comportamiento y posibles errores en la interacción entre los componentes y demás elementos.
  • GUI Test / End-to-end Tests: Comprobar los errores en la interfaz de usuario, que es la donde nos centraremos con este curso. Es el parte más elaborada ya que depende de los demás niveles.

Algunas características del End-to-end Testing:

  • Prueba todo el flujo del software desde el punto de vista del usuario final.
  • Prueba el software desde la interfáz de usuario y no desde el código interno.
  • Está enfocado en detectar posibles problemas que pudieran encontrar nuestros usuarios en su interacción con el flujo general del programa.

Qué es Cypress

Para realizar el End-to-end testing (e2e) es necesario disponer de una herramienta que simule la interacción de los usuarios con el navegador, y en ese punto es donde usaremos cypress, ya que es un framework que nos permite simular esa interacción.

En el caso de que nuestra aplicación necesite hacer uso de un backend, será necesario utilizar una copia del mismo y que sea lo más exacta a la desplegada en producción.

Principales ventajas

  • No usa Selenium por lo que es muy sencillo de integrar.
  • Está hecho con Electron lo que le da acceso y control a una instancia de Chrome u otro navegador.
  • Está enfocado exclusivamente en hacer e2e testing, y hacerlo muy bien.
  • Funciona con cualquier librería o framework de frontend siempre que corran en un navegador.
  • Los tests están escritos en JavaScript.
  • Es un todo-en-uno, por lo que no requiere la instalación de paquetes de terceros para funcionar, sin embargo se puede extender su funcionalidad con módulos adicionales.
  • Es mucho más rápido que cualquier otra alternativa existente a la fecha.

Empezando con cypress

Como había indicado al principio de la entrada, vamos a usar el proyecto que estamos creando en el curso de VueJS o cualquier otro que tengamos, básicamente para intentar enfocarnos en el testing y no dedicar en este momento mucho tiempo al desarrollo.

Empezaremos instalando cypress con el siguiente comando: npm i cypress -D

Cuando el proceso de instalación de cypress haya finalizado, entonces añadiremos un pequeño script en el fichero package.json.

{
  "name": "omdb",
  "description": "A Vue.js project",
  "version": "1.0.0",
  "author": "Ivan <kimagure44@yahoo.es>",
  "license": "MIT",
  "private": true,
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
    "test": "cypress open --project ./test"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.8",
    "@fortawesome/free-solid-svg-icons": "^5.5.0",
    "@fortawesome/vue-fontawesome": "^0.1.2",
    "axios": "^0.18.0",
    "vue": "^2.5.11",
    "vue-router": "^3.0.2"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "@fortawesome/fontawesome-free": "^5.5.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "cypress": "^3.1.5",
    "eslint": "^5.9.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-html": "^5.0.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^8.0.0",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "file-loader": "^1.1.4",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1"
  }
}

Al ejecutar ese script se nos creara una carpeta llamada test con una estructura básica para que cypress funcione.

Para saber que nos ha creado la ejecución de ese script vamos a explicar que es y que contiene cada carpeta:

  • fixtures: Contiene los ficheros donde definiremos nuestras variables y mockups que luego usaremos en nuestros test.
  • integration: Contiene los ficheros que usaremos para realizar los test.
  • plugins: Contiene los plugins para cypress.
  • support: Creamos código para que se ejecute después de cada test.

Ahora ya sabemos que ha ocurrido cuando ejecutamos el script que añadimos a package.json, ademas de esa estructura también nos abrirá la consola de cypress para realizar los test.

y nos abrirá una consola para ejecutar todos los test o uno a uno.

En la imagen anterior vemos todos los test que crea por defecto cypress la primera vez, y que los podemos usar como consulta o simplemente borrarlos.

Como nos gustaría probar cypress y de momento no tenemos ningún test creado, vamos a ejecutar los test que vienen por defecto.

Con esa ejecución podemos ver todo o casi todo lo que podemos hacer con cypress.

Todo lo anterior esta muy bien, pero vamos a comenzar con nuestro test, nuestro primer test e2e.

Lo primero que necesitamos es arrancar nuestra aplicación, ya que cypress necesitar que nuestra aplicación este preparada para poder ejecutar los test en el navegador.

Para ello vamos a arrancar nuestro servidor con el siguiente comando desde la consola: npm run dev, que en nuestro caso es el proyecto que estamos haciendo en el curso de Vue.

Con el servidor iniciado y nuestra aplicación en funcionamiento vamos ahora abrir otra consola de comandos y ejecutaremos el siguiente comando: npm run test.

Como información extra, con el comando npm run xxxxx lo que estamos ejecutando es el nombre del script que se ha definido dentro del package.json. 

Si lo ejecutamos ahora mismo como no tenemos ningún test ya que eliminamos los test de prueba, cypress nos indicara que no tenemos ningún test.

Nuestro primer test

Nuestros tests los crearemos en la carpeta integration ubicada dentro de cypress.

Cada set de pruebas lo realizaremos en un archivo de JavaScript individual que identificaremos como xxxxxx.spec.js

Cypress trae integradas las funcionalidades de mochaJS y las aserciones de ChaiJS, así que si trabajaste con estas herramientas de testing la sintaxis de cypress te sonara bastante.

La estructura básica de un test es esta:

describe('Nombre del test', () => {
  it('Descripción de la prueba', ()  => {
    // --- comandos de cypress
  });
});

Con describe definimos un conjunto de pruebas y con it definimos un test individual.

Aunque mas adelante veremos como configurar cypress usando el fichero cypress.json, ahora vamos a configurar una opción básica para tener definida una url base para nuestros test de nuestro proyecto.

{
  "baseUrl": "http://localhost:8080"
}

Con el siguiente test vamos ha comprobar algo muy básico, que es la navegación a una web:

describe('Search a film', () => {
  it('Search the title of a movie and show the information', () => {
    cy.visit('/');
  });
});

En la siguiente imagen veremos lo que a ocurrido al guardar el test:

Para finalizar esta primera parte del curso añadiremos un par de lineas de código a nuestro test y en la siguiente parte del curso continuaremos implementado mas test a nuestra aplicación y algunos conceptos avanzados.

describe('Search a film', () => {
  it('Search the title of a movie and show the information', () => {
    cy.visit('/');
    cy.get('.box-search input').type('indiana jones');
    cy.get('.box-search a').click();
  });
});