DEV Community

Rubén Aguilera Díaz-Heredero
Rubén Aguilera Díaz-Heredero

Posted on • Updated on

Cobertura de tests con Vite, Cypress, Vitest y Docker

Introducción

Cypress es una tecnología que, entre otras cosas, nos permite hacer testing e2e de nuestras aplicaciones web sin preocuparse por la tecnología que estemos utilizando por debajo, haciendo que se reduzca nuestro esfuerzo cognitivo de tener que aprender como testear la capa de UI en cada framework.

Pero no deja de ser interesante conocer la cobertura que estos tests tienen sobre todo nuestro código e incluso mergearla con la cobertura de los tests unitarios en la capa de core.

En este tutorial vamos a ver cómo hacer todo esto, partiendo de que nuestro proyecto ya tiene instalado Cypress como vimos en el tutorial Empezando con Cypress

Levantar el proyecto antes de ejecutar Cypress

Para poder ejecutar las pruebas e2e con Cypress tenemos que tener nuestro proyecto web levantado, además cuando ejecutamos estas pruebas en un pipeline necesitamos asegurarnos de que el servidor está levantado antes de ejecutarlas, ¿cómo podemos hacer esto?

La respuesta es instalar la siguiente dependencia:

$> npm install --save-dev start-server-and-test
Enter fullscreen mode Exit fullscreen mode

y establecer dentro de nuestro package.json un nuevo script que nos permita ejecutar los tests de cypress justo después del arranque de la aplicación.

{
  "name": "spa-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "cy:open": "cypress open",
    "cy:test": "cypress run",
    "test:ci": "start-server-and-test dev http-get://localhost:5173 cy:test"
  },
  "dependencies": {
    "lit": "^2.7.2"
  },
  "devDependencies": {
    "cypress": "^12.17.3",
    "start-server-and-test": "^2.0.0",
    "vite": "^4.3.9"
  }
}
Enter fullscreen mode Exit fullscreen mode

Es importante tener en cuenta el puerto dond ese vaya a levantar la aplicación, en este caso, el "5173" y el script que usamos para levantarla que en este caso es "dev".

De esta forma, ya podemos ejecutar:

$> npm run test:ci
Enter fullscreen mode Exit fullscreen mode

y nuestros tests solo se ejecutaran en el terminal cuando el servidor se haya levantado.

Cálculo de la cobertura

Para realizar el cálculo de la cobertura necesitamos incluir las siguientes dependencias de desarrollo:

$> npm install --save-dev @cypress/code-coverage istanbul istanbul-merge nyc vite-plugin-istanbul
Enter fullscreen mode Exit fullscreen mode

Ahora configuramos el fichero vite.config.js dejándolo de esta forma:

import { defineConfig } from "vitest/config";
import istanbul from "vite-plugin-istanbul";

export default defineConfig({
  plugins: [
    istanbul({
      cypress: true,
      requireEnv: false,
    }),
  ],
  test: {
    environment: "jsdom",
  },
});
Enter fullscreen mode Exit fullscreen mode

Añadimos la siguiente línea al fichero cypress/support/e2e.js:

import '@cypress/code-coverage/support'
Enter fullscreen mode Exit fullscreen mode

En el fichero cypress.config.js sustituimos el bloque actual por este otro:

import { defineConfig } from "cypress";
import codeCoverageTask from "@cypress/code-coverage/task.js";

export default defineConfig({
  video: false,
  e2e: {
    baseUrl: "http://localhost:5173",
    setupNodeEvents(on, config) {
      codeCoverageTask(on, config);
      return config;
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Ahora creamos el fichero .nycrc con el siguiente contenido para configurar nuestros reportes de cobertura:

{
    "all": true,
    "check-coverage": true,
    "instrument": false,
    "report-dir": "coverage/cypress",
    "include": [
      "src/**"
    ],
    "exclude": [
      "instrumented/**"
    ],
    "lines": 0, //% mínimo, por debajo lanza error
    "statements": 0, //% mínimo, por debajo lanza error
    "functions": 0, //% mínimo, por debajo lanza error
    "branches": 0 //% mínimo, por debajo lanza error
}
Enter fullscreen mode Exit fullscreen mode

Añadimos los siguientes scripts a nuestro package.json para hacer limpieza de los directorios, ejecutar los test de cypress con su cobertura, y generar los reportes correspondientes:

...
"clean:cov": "rm -rf coverage .nyc_output",
"test:ci": "start-server-and-test start http-get://localhost:5173/ cy:test",
"report:cov": "nyc report --reporter html --reporter text --reporter lcov -t coverage/cypress --report-dir coverage/cypress",
...
Enter fullscreen mode Exit fullscreen mode

De esta forma al ejecutar:

$> npm run test:ci
Enter fullscreen mode Exit fullscreen mode

Veremos que al finalizar los test nos genera los reportes de cobertura de cypress dentro del directorio "coverage/cypress".

Mergear la cobertura de Cypress y Vitest

Llegados a este punto, tenemos dos informes de cobertura, el primero de los tests con Vitest que tenemos dentro de la carpeta "coverage" y el segundo de los tests de cypress que encontramos en la carpeta "coverage/cypress".

Para ver un informe conjunto de ambos y saber cuál es el grado de cobertura de todos los tests en conjunto, hacemos uso de la utilidad "istanbul-merge".

De forma que teniendo esta sección de scripts dentro de nuestro package.json:

"scripts": {
    "start": "vite",
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "test": "vitest run --coverage --reporter junit --outputFile reports/junit-reporter.xml",
    "sonar": "sonar-scanner",
    "cy:open": "cypress open",
    "cy:test": "cypress run",
    "clean:cov": "rm -rf coverage .nyc_output test/reporter.xml",
    "test:ci": "start-server-and-test start http-get://localhost:5173/ cy:test",
    "cov:merge": "istanbul-merge --out coverage/total/coverage.json coverage/coverage-final.json coverage/cypress/coverage-final.json",
    "report:cov": "nyc report --reporter cobertura --reporter html --reporter text --reporter lcov -t coverage/total --report-dir reports/coverage",
    "test:all": "npm run clean:cov && npm run test && npm run test:ci && npm run cov:merge && npm run report:cov"
  }
Enter fullscreen mode Exit fullscreen mode

Podemos ejecutar:

$> npm run test:all
Enter fullscreen mode Exit fullscreen mode

De forma que se van a limpiar los directorios generados, se van a lanzar los tests de Vitest con su cobertura, se van a lanzar los tests de Cypress con su cobertura, se van a mergear en una única fuente de cobertura, se van a generar los reportes lcov, html y vamos a poder ver el resultado final también en la terminal.

Nota: es importante actualizar nuestro fichero .gitignore añadiendo los directorios que no queremos subir a nuestro control de versiones:

dist/
node_modules/
coverage/
.nyc_output/
Enter fullscreen mode Exit fullscreen mode

Ejecución con Docker & Docker Compose

Para que estos tests aporten valor real al proyecto, tienen que formar parte del proceso de integración continua de nuestro proyecto.

Una de las formas más universales que tenemos de hacer esto, es hacer uso de Docker & Docker Compose y ejecutarlo en nuestro pipeline.

Para ello vamos a crear un fichero Dockerfile.cy con el siguiente contenido:

FROM cypress/included:12.17.3

WORKDIR /workspace

COPY package.json ./

RUN npm install --unsafe-perm=true --allow-root

COPY . .
Enter fullscreen mode Exit fullscreen mode

Y un fichero docker-compose.ci.yml con el siguiente contenido:

version: "3.7"

services:
  test_all:
    build:
      context: .
      dockerfile: Dockerfile.cy
    entrypoint: /bin/sh -c "npm run test:all"
    volumes:
      - ./reports:/workspace/reports
Enter fullscreen mode Exit fullscreen mode

Si nuestro pipeline fuera con GitlabCI, podríamos definir un stage de esta forma:

validate:
  stage: validate
  script:
    - docker-compose -f docker-compose.ci.yml up test_all --build --exit-code-from=test_all || exit 1
  tags:
    - runner101-shell
  except:
    - tags
  artifacts:
    reports:
      junit:
        - reports/junit-reporter.xml
      coverage_report:
        coverage_format: cobertura
        path: reports/coverage/cobertura-coverage.xml
  timeout: 600 seconds
Enter fullscreen mode Exit fullscreen mode

Donde ejecutamos el script test:all al proyecto dentro de los stages de nuestro pipeline y podemos consultar los reportes generados para ser visualizados en nuestras Merge Requests.

Top comments (1)

Collapse
 
suichim profile image
Esteban Martini

Excelente!