cypress

PROPÓSITO

  • Para probar cypress como ayuda para testear aplicaciones web.

INSTALACIÓN

  • aunque lo puedes descargar recomiendan instalarlo con npm
# PARA INICIAR EL PROYECTO NPM
npm init
# PARA INSTALAR CYPRES DE FORMA LOCAL CON EL NODE_MODULES EN EL PROYECTO
npm install cypress --save-dev
# PARA INSTALAR CYPRES DE FORMA GLOBAL CON EL NODE_MODULES POR EJEMPLO EN C:\Users\javier\AppData\Roaming\npm\node_modules\
npm install -g cypress --save-dev
# PARA INICIAR CYPRESS Y QUE SE CREE LA ESTRUCTURA DE DIRECTORIOS CON EJEMPLOS
node_modules\.bin\cypress open
  • los binarios se descargan en C:\Users\javier\AppData\Local\Cypress\Cache

  • estos comandos instalarán cypress, lo pondrán como dependencia en tu proyecto npm y crearán una estructura básica con ejemplos de prueba

  • para actualizar de versión

    • npm install --save-dev cypress@6.0.1
    • node install
    • con esta forma si lanzas node_modules\.bin\cypress open se abre cypress 6.0.1 y si solo usas cypress open se abre cypress general que es el que esta en C:\Users\javier\AppData\Local\Cypress\Cache\4.4.1\Cypress 4.4.1
    • pero no veo esta ruta en la path de variables de entorno
      • en esta carpeta C:\Users\javier\AppData\Roaming\Microsoft\Windows\Recent hay dos enlaces a la referencia que se ve pero no se si se usan o porque están allí
    • no funciona npm i cypress
  • CYPRESS_CACHE_FOLDER debe ser la clave de porque se usa la versión 4.4.1 con cypress

  • para borrar los ejemplos de cypress que se instalan en el primer uso

# Delete all Cypress example tests
rm -rf cypress/integration/examples

VERSIÓN

  • cypress --version
  • 2020-12-06 18:19:34 tengo la versión 4.4.1
  • pero en cada proyecto instalo una versión más actual

INFO

  • cypress info para sacar información de cypress general
  • node_modules\.bin\cypress info para sacar la información de la instalación en el proyecto

CARACTERÍSTICAS

  • 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 (end to end) testing, y hacerlo muy bien.
  • Funciona con cualquier librería o framework de frontend siempre que corra 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.
  • A pesar de haber usado Katalon me sorprende gratamente lo rápido que funciona y lo sencillo que es de usar
  • recomiendan usarlo para aplicaciones que estas desarrollando tu mismo y solo para probarlas durante el desarrollo diario
  • insisten es que no es una herramienta para automatización web de propósito general.

VARIABLES EN CYPRESS

VISUAL TESTING

CYPRESS-IMAGE-SNAPSHOT

PERCY

  • para hacer test visuales se puede usar percy que se puede integrar con cypres
  • un ejemplo de integración

CONSEJOS

  • con el test runner funcionando ni siquiera hace falta guardar el archivo para que se ejecute y se vea el cambio
  • en el script meter comentarios sobre que parte de la aplicación estas en cada momento pues ayuda bastante al desarrollo
  • hacer capturas de pantalla con nombre de fichero que incluya un orden de ejecución cy.screenshot('1-nomina-creada') como forma de tener pruebas de que todo ha ido bien
    • se puede hacer captura incluso de un elemento concreto cy.get('.seemTd100AlignIzq > .pequena2').screenshot('1-version')
    • si no se pone nombre a la captura de pantalla el propio programa pone el nombre descriptivo de en que parte del código se ha tomado la captura lo que puede ser bastante útil
  • atención pues la ejecución del test borra el vídeo y las capturas de pantalla de la anterior ejecución
  • poner en el archivo cypress.json la baseURL "baseUrl": "http://localhost:8080" del proyecto para facilitar las pruebas

TEST STUDIO

  • Cypress Studio
  • a partir de la versión 6.3
  • es necesario activarlo en cypress.json
"experimentalStudio": true ,

TEST RUNNER

  • así se ve al lanzar el comando open

CYPRESS_TEST_RUNNER

  • luego se selecciona el test a probar y se ejecuta

CYPRESS_TEST_RUNNER

  • el selector es super útil para generar el código que luego vas a meter en el script
CYPRESS_TEST_RUNNER

DASHBOARD

  • se puede usar la web de cypress para ver los resultados usando el dashboard

  • para que se guarden los test en el dashboard hay que lanzar el test con la opción --record

  • antes tienen que conseguir un id del proyecto

  • para eso te validas en la web

    • puedes ver tus proyectos
    • cuando crea uno te indica como actuar
    • y lanzas el test con esta instrucción
cypress run --spec "cypress\integration\EPNOM_ADM\APLICACION_USUARIOS.js" --config-file cypress\config\cypress.preaplicaciones.json --record --key 21ea6b64-5939-41b0-a628-2d72b2ad7c62`
  • se pone el projectId en el archivo cypress.json pero en este caso como el archivo de configuración no es el general hay que ponerlo en el archivo que se usa
  • nada más lanzar el test se puede ver su evolución en el web
  • el resultado es espectacular y con muchas opciones por descubrir

TESTEAR VARIAS CONDICIONES

cy.get('.assertions-link')
  .should('have.class', 'active')
  .and('have.attr', 'href')
  .and('include', 'cypress.io')

CONFIGURAR LA RESOLUCIÓN DE LOS TEST

  • desde la línea de comandos
  • npx cypress run --config viewportWidth=320 viewportHeight=480

EJEMPLO

describe('inicio', () => {
  // esto se ejecuta en todos los tests
  beforeEach(() => {
    cy.log('Comienzo del test')
    // la pantalla de inicio
    // cy.visit('localhost:8080/epnom_adm/start.action?idUsuario=jiranzo&idAplicacion=48&token=1')
    cy.visit('/epnom_adm/start.action?idUsuario=jiranzo&idAplicacion=48&token=1')
  })
  it('Successful inicio', () => {
    // captura de la versión del programa
    cy.get('.seemTd100AlignIzq > .pequena2').screenshot('1-version')
    // cy.screenshot()
    // vamos a la primera opción de menú importante
    // Nóminas
    cy.get('.nivel1_800 > :nth-child(3)')
    .click()
    // tiene que salir la nómina activa
    cy.contains('Nómina activa')
    // vamos a añadir nómina
    cy.get('[title="Añadir Nómina"]')
    .click()
    cy.get('#nomprocessagnadirnomina_nomina_descripcion')
    .type(' Nómina para TEST')
    cy.get('#aceptar')
    .click()
    // comprobando que la creación ha sido correcta
    cy.contains('La operación se ha realizado correctamente')
    cy.contains('Nómina para TEST')
    cy.screenshot('2-nomina-creada')
    // vamos a modificar la nómina creada
    cy.get(':nth-child(2) > :nth-child(5) > a > .sinBorde')
    .click()
    cy.get(':nth-child(3) > .textoApl1 > a')
    .click()
    cy.contains('Datos Generales')
    cy.get('#modificar')
    .click()
    cy.contains('Modificar Datos Generales')
    cy.get('#nomprocessmodificardatosgenerales_nominaaux_descripcion')
    .type(' MODIFICADO')
    cy.get('#aceptar')
    .click()
    // comprobando que la modificación ha sido correcta
    cy.contains('La operación se ha realizado correctamente')
    cy.contains('Nómina para TEST MODIFICADO')
    cy.screenshot('3-nomina-modificada')
    cy.get(':nth-child(7) > a')
    .click()
    // vamos a borrar la nómina creada
    cy.get(':nth-child(2) > :nth-child(6) > a > .sinBorde')
    .click()
    cy.contains('Eliminar Nómina')
    cy.get('#aceptar')
    .click()
    // comprobando que el borrado ha sido correcto
    cy.contains('La operación se ha realizado correctamente')
    cy.screenshot('4-nomina-eliminada')
    // vamos a buscar nóminas
    cy.get('[title="Buscar Nóminas"]')
    .click()
    // comprobamos que sale al año actual
    cy.get('#nomprocessbuscarnominas_formbusqueda_idagno').contains('2020')
    // volvemos a la primera opción de menú importante ç
    // Nóminas
    cy.get('.nivel1_800 > :nth-child(3)')
    .click()
    
    // vamos a consultar la nómina activa 
    cy.get(':nth-child(4) > a > .sinBorde')
    .click()
    // tiene que salir la nómina activa
    cy.contains('Gestión de la Nómina')
    // vamos a gestión de perceptores de nómina
    cy.get(':nth-child(4) > .textoApl1 > a')
    .click()
    cy.contains('Búsqueda de perceptores')
    cy.get('#buscar')
    .click()
    cy.screenshot('5-perceptores de nómina buscados')
    // comprobamos que la consulta funciona 
    cy.contains('Se han encontrado 436 registros.')
  })
})
  • y esta es la salida del ejemplo
C:\proyectos\cypress\inicio>node_modules\.bin\cypress run --spec  "cypress\integration\EPNOM_ADM\*.*"


====================================================================================================

  (Run Starting)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:    4.3.0                                                                              │
  │ Browser:    Electron 80 (headless)                                                             │
  │ Specs:      1 found (EPNOM_ADM\NAVEGANDO_DESARROLLO_LOCAL.js)                                  │
  │ Searched:   cypress\integration\EPNOM_ADM\*.*                                                  │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


────────────────────────────────────────────────────────────────────────────────────────────────────

  Running:  EPNOM_ADM\NAVEGANDO_DESARROLLO_LOCAL.js                                         (1 of 1)


  inicio
    √ Successful inicio (16397ms)


  1 passing (16s)


  (Results)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Tests:        1                                                                                │
  │ Passing:      1                                                                                │
  │ Failing:      0                                                                                │
  │ Pending:      0                                                                                │
  │ Skipped:      0                                                                                │
  │ Screenshots:  5                                                                                │
  │ Video:        true                                                                             │
  │ Duration:     16 seconds                                                                       │
  │ Spec Ran:     EPNOM_ADM\NAVEGANDO_DESARROLLO_LOCAL.js                                          │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


  (Screenshots)

  -  C:\proyectos\cypress\inicio\cypress\screenshots\EPNOM_ADM\NAVEGANDO_DESARROLLO_L       (212x12)
     OCAL.js\1-version.png
  -  C:\proyectos\cypress\inicio\cypress\screenshots\EPNOM_ADM\NAVEGANDO_DESARROLLO_L     (1000x660)
     OCAL.js\2-nomina-creada.png
  -  C:\proyectos\cypress\inicio\cypress\screenshots\EPNOM_ADM\NAVEGANDO_DESARROLLO_L     (1000x660)
     OCAL.js\3-nomina-modificada.png
  -  C:\proyectos\cypress\inicio\cypress\screenshots\EPNOM_ADM\NAVEGANDO_DESARROLLO_L     (1000x660)
     OCAL.js\4-nomina-eliminada.png
  -  C:\proyectos\cypress\inicio\cypress\screenshots\EPNOM_ADM\NAVEGANDO_DESARROLLO_L     (1000x915)
     OCAL.js\5-perceptores de nómina buscados.png


  (Video)

  -  Started processing:  Compressing to 32 CRF
  -  Finished processing: C:\proyectos\cypress\inicio\cypress\videos\EPNOM_ADM\NAVEGA     (1 second)
                          NDO_DESARROLLO_LOCAL.js.mp4


====================================================================================================

  (Run Finished)


       Spec                                              Tests  Passing  Failing  Pending  Skipped  
  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ √  EPNOM_ADM\NAVEGANDO_DESARROLLO_LOCA      00:16        1        1        -        -        - │
  │    L.js                                                                                        │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘
    √  All specs passed!                        00:16        1        1        -        -        -  

  • la salida explica el resultado del test, donde deja las capturas de pantalla y donde el vídeo de salida

REPORT MEJORADO

  • la salida del test son los reportes que pueden ser distintos aunque el que viene por defecto esta bien

  • un blog explicando como instalar mochawesome con buenas explicaciones sobre como usar los scripts en package.json

  • cypress run --reporter mochawesome

USO SIN SERVIDOR

PROYECTO DE INICIO

  • uso este proyecto para probar cosas que luego se pasan a los test de los proyectos concreto
  • en el directorio de inicio C:\proyectos\cypress\INICIO_CYPRESS>
  • probar cy.url().should(‘not.include’, ‘login’) para la condición contraria not contains

COMANDOS

// para arrancar el test runner
node_modules\.bin\cypress open
//  esto arranca la aplicación con ejemplos y bastante buena pinta

// para lanzar el test sin el test runner
node_modules\.bin\cypress run
// esto por defecto lanza los tests de la carpeta cypress\integration\examples 
// con un navegador silencioso llamado Electron
// graba un video con el resultado

// para lanzar un test en concreto
node_modules\.bin\cypress run --browser chrome --spec "cypress\integration\examples\login.preEPCNT.js"
node_modules\.bin\cypress run --browser chrome --spec "cypress\integration\examples\PROBANDO_DESARROLLO_LOCAL.js"
node_modules\.bin\cypress run --spec  "cypress\integration\EPNOM_ADM\PRUEBA.JS"

// para lanzar los tests de un directorio concreto
node_modules\.bin\cypress run --spec  "cypress\integration\EPNOM_ADM\*.*"
  • cy.pause() muy interesante para crear el test y ver como se desarrolla

INTELLISENSE

  • para añadir intellisense a un documento de test en cypress
/// <reference types="Cypress" />
  • funciona muy bien

SELECCIÓN DE ELEMENTOS

PARA SELECCIONAR ELEMENTOS ALEATORIAS CON CYPRESS

  • para random
  • clono el proyecto en C:\proyectos\cypress\iCinema>

FORMA SENCILLA DE SELECCIÓN DE ELEMENTOS

// Find an element in the document containing the text 'New Post'
cy.contains('New Post')

// Find an element within '.main' containing the text 'New Post'
cy.get('.main').contains('New Post')

cy.get('.busqueda > h1').should('be.visible').and('contain', 'Buscando');

cy.get(':checkbox').should('be.disabled')

cy.get('form').should('have.class', 'form-horizontal')s

cy.get('input').should('not.have.value', 'US')

SELECTORES CSS

  • me instalo un plugin de Chrome llamado CSS Selector Capture

  • para usarlo de forma fácil le tengo que asociar una tecla rápida Ctr + Mayúscula + A por ejemplo

  • como la selección es dinámica sirve para aprender como se puede referenciar los elementos.

  • la ayuda con videos

  • con la opción verbose no activada la selección es menos larga

  • me instalo el plugin selectorGadjet

    • para poder usarlo en combinación con el anterior
    • este se puede fijar a la barra de marcadores
  • de todas forma aprender a usar los selectores CSS y a entenderlos

START-SERVER-AND-TEST

EJEMPLO PARA ESTE SITIO

  • lo uso para este mismo proyecto
  • se lanza con npm run ci
  • de esta forma se lanza el script "ci": "start-server-and-test http://localhost:1313" que es como si lanzaras "ci": "start-server-and-test start http://localhost:1313 test"
    • si tus scripts para lanzar el servidor se llama start y para los tests test como sigues la convención de npm no hace falta ponerlos
  • de esa forma se crea el sitio con Hugo, se borra el directorio public para volver a lanzar la creación del sitio y el servidor desde memoria
  • luego se lanza el test y se cierra el servidor

EJEMPLO PARA UNA APLICACIÓN PADDOC

CONFIGURAR EL VIEWPORT

  • para evitar problemas con las pantallas que ocultan el menú lateral si la vista es pequeña se puede configurar el viewport en el archivo cypress.json
  "viewportWidth": 1300,
  "viewportHeight": 900

VARIABLES

VARIOS TESTS

  • cada it es un test
  • si tienes varios y solo quieres ejecutar uno para probar ese se usa it.only
  • si quieres excluir un test it.skip

CAMBIAR EL DIRECTORIO DE DESCARGA

MULTIPLES ENTORNOS

CAPTURAR ERRORES

  • para evitar errores de ejecución se puede usar lo que aconsejan en este post de cypress
    • lo uso en el proyecto CYPRESS-INICIO para los tests de varios-viewport que daban error en la mitad de ellos y funciona bien

PLUGINS

PACKAGE.JSON

  • un ejemplo que se puede seguir
  • esta pensado para usar next.js pero se puede adaptar para cualquier proyecto con cypress
{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "cypress": "cypress open",
    "cypress:headless": "cypress run",
    "e2e": "start-server-and-test dev http://localhost:3000 cypress",
    "e2e:headless": "start-server-and-test dev http://localhost:3000 cypress:headless"
  },
  "dependencies": {
    "next": "latest",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "cypress": "8.2.0",
    "start-server-and-test": "1.13.1"
  }
}

PAGE OBJECT

TUTORIALES

LOS DE CYPRESS

TOOLSQA

GLEB BAHMUTOV

OTROS TUTORIALES

EJEMPLO DE CYPRESS

  • en el directorios cypress-realworld-app esta el ejemplo hecho en react bastante interesante y que funciona
  • de este ejemplo se puede aprender mucho

TYPESCRIPT Y PAGE OBJECT

EXPERTOS

CYPRESS.JSON

  • se configura cypress en este archivo
// atención pues los comentarios dan problemas en archivos json
{
  "viewportWidth": 1300,
  "viewportHeight": 900,
  "experimentalStudio": true,
  "watchForFileChanges": false
}

PROBLEMAS

ARCHIVOS DE LOGS REPETIDOS

CHROMEWEBSECURITY

Another caveat: If you’re testing your own app, the need to navigate to another domain may be rare, and it’s for this reason this test would fail if we didn’t add “chromeWebSecurity”: false in our cypress.json config.

CANIUSE-LITE IS OUTDATED

  • sale al lanzar un test en local
  • Browserslist: caniuse-lite is outdated. Please run the following command: npx browserslist –update-db``
  • lanzo la instrucción pero sigue saliendo y al final deja de salir con npm update

INSTALAR CYPRESS GLOBAL

  • no recomiendan instalar cypress de forma global
‼ Warning: It looks like you've installed Cypress globally.

  This will work, but it's not recommended.

  The recommended way to install Cypress is as a devDependency per project.

  You should probably run these commands:

  - npm uninstall -g cypress
  - npm install --save-dev cypress

BEFORE EACH

  • si se lanza una prueba para varios usuarios y se pone el login en un hook before each el navegador abre todas las conexiones una en cada pestaña con lo que al compartir sesión se queda el último usuario conectado
    • las capturas ponían el nombre del usuario que le tocaba pero en la pantalla capturada salía el nombre de último conectado
    • lo soluciono repitiendo el código de conexión en cada test

PRIMERAS PRUEBAS FIREWALL

  • conviene lanzar las primeras pruebas con el comando cypress open para que salga el mensaje pidiendo permiso para pasar el firewall

UNCAUGHT EXCEPTIONS

  • sale un error cuando la aplicación tiene algún error que se puede ver en la consola aunque funciona correctamente
 Uncaught ReferenceError: b$ is not defined

This error originated from your application code, not from Cypress.

When Cypress detects uncaught errors originating from your application it will automatically fail the current test.

This behavior is configurable, and you can choose to turn this off by listening to the `uncaught:exception` event.

https://on.cypress.io/uncaught-exception-from-application
  • se soluciona de esta forma
// likely want to do this in a support file
// so it's applied to all spec files
// cypress/support/index.js

Cypress.on('uncaught:exception', (err, runnable) => {
  // returning false here prevents Cypress from
  // failing the test
  return false
})
  • se tiene que poner en el archivo cypress/support/index.js

EXCEDE EL TIMEOUT AL CARGAR UNA PÁGINA

  • la prueba en DESEDUCA no cargaba EPACF y sin embargo si que la cargaba en PREEDUCA
    • en la configuración de la aplicación tenía puesto http://despaddoc.aragon.es/epacf/start.action pero no por https lo que bloqueaba la página
    • es IMPORTANTE ver lo que pone en las herramientas de desarrollo pues es allí donde he encontrado la pista
    • antes había aumentado el timeout para esa prueba añadiendo Cypress.config('pageLoadTimeout', 100000) al inicio del test

IS BEING COVERED BY ANOTHER ELEMENT

  • Timed out retrying: cy.click() failed because this element:
    • is being covered by another element:
  • se soluciona usando .click({force : true})

POR VER

// this only works if there's 100% guarantee
// body has fully rendered without any pending changes
// to its state
cy.get('body').then(($body) => {
    // synchronously ask for the body's text
    // and do something based on whether it includes
    // another string
    if ($body.text().includes('some string')) {
      // yup found it
      cy.get(...).should(...)
    } else {
      // nope not here
      cy.get(...).should(...)
    }
  })
  • un post de iniciación interesante
    • muestra como crear un archivo con los selectores que vas a usar en los tests en el directorio support
      • se puede usar para el botón Aceptar que se repite en muchos tests

CANALES

PARA PRUEBAS

GITIGNORE

  • para los gitignore con cypress basado en el que usan los programadores de cypress
node_modules/
cypress/videos
cypress/screenshots/

POR ORDENAR

cy.get('body').then(($body) => {
    if ($body.text().includes('some string')) {
      cy.get().should()
    } else {
      cy.get().should()
    }
  })