Cobertura de tests con Vite, Cypress, Vitest y Docker
Tags: vite, vitest, cypress, docker
Published: 2023-08-12 23:15:54

---
published: true
title: "Cobertura de tests con Vite, Cypress, Vitest y Docker"
cover_image: 
description: 
tags: vite, vitest, cypress, docker
series: cypress
canonical_url:
---

## 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](https://dev.to/raguilera82/empezando-con-cypress-7g3)

## 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:

```bash
$> npm install --save-dev start-server-and-test
```
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.

```javascript
{
  "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"
  }
}
```
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:

```bash
$> npm run test:ci
```
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:

```bash
$> npm install --save-dev @cypress/code-coverage istanbul istanbul-merge nyc vite-plugin-istanbul
```
Ahora configuramos el fichero vite.config.js dejándolo de esta forma:

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

export default defineConfig({
  plugins: [
    istanbul({
      cypress: true,
      requireEnv: false,
    }),
  ],
  test: {
    environment: "jsdom",
  },
});
```
Añadimos la siguiente línea al fichero cypress/support/e2e.js:

```javascript
import '@cypress/code-coverage/support'
```
En el fichero cypress.config.js sustituimos el bloque actual por este otro:

```javascript
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;
    },
  },
});
```
Ahora creamos el fichero .nycrc con el siguiente contenido para configurar nuestros reportes de cobertura:

```javascript
{
    "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
}
```
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:

```javascript
...
"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",
...
```
De esta forma al ejecutar:

```bash
$> npm run test:ci
```
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:

```javascript
"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"
  }
```
Podemos ejecutar:
```bash
$> npm run test:all
```
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:

```text
dist/
node_modules/
coverage/
.nyc_output/
```

## 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:
```dockerfile
FROM cypress/included:12.17.3

WORKDIR /workspace

COPY package.json ./

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

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

```yaml
version: "3.7"

services:
  test_all:
    build:
      context: .
      dockerfile: Dockerfile.cy
    entrypoint: /bin/sh -c "npm run test:all"
    volumes:
      - ./reports:/workspace/reports
```
Si nuestro pipeline fuera con GitlabCI, podríamos definir un stage de esta forma:

```yaml
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
```
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.