Skip to main content

Informes

Vamos a trabajar con el reports y generar los informes del modo correcto.

La mayoría de las herramientas que hacen algún tipo de análisis pueden mostrar el resultado en la consola (terminal), pero también pueden generar un archivo estructurado con el resultado del análisis, que es lo que llamamos report.

La configuración de report del test unitario está en el archivo vite.config.js

export default defineConfig({
plugins: [react()],
build: {
outDir: 'build'
},
test: {
environment: 'jsdom',
setupFiles: './tests/setup.js',
exclude: [
'**/node_modules/**',
'**/dist/**',
'**/e2e/**'
],
reporters: ['verbose', 'junit', 'html'], // <<<<< está generando de los dos modos
outputFile: {
junit: './reports/junit.xml', // <<<< para formato junit
html: './reports/html/index.html' // <<<< para formato html
}
}
})

O sea, el report saldrá en este archivo ./reports/junit.xml, aunque se muestre algo vía consola. Ese archivo contendrá información detallada sobre los tests.

En nuestro job de test unitario vamos a generar el artefacto para ese report del modo correcto. Vamos a usar always para garantizar que siempre dará el report, o falla o no.

unit-test:
stage: test
image: node:22-slim
script:
- npm ci
- npm test
artifacts:
when: always
expire_in: "1 week"
reports:
junit: reports/junit.xml

Vamos a subir el código con la modificación solamente en este job.

git checkout -b pipe/reports
git add .gitlab-ci.yml
git commit -m "add reports to unity tests"
git push origin pipe/reports

alt text

alt text

alt text

El hecho de usar la etiqueta junit (artifacts.reports.junit) avisa a GitLab que este es un archivo en formato junit y automáticamente GitLab hace un "parser" para hacer la visualización correcta en la interfaz.

Así podemos navegar entre el informe de manera simple e igual para varios informes.

Nada impide que publiquemos el archivo en reports y paths al mismo tiempo para que podamos hacer la descarga en caso necesario.

¿Cómo hacemos lo mismo ahora para el linter? Primero vamos a volver lo que teníamos antes en package.json

{
"scripts": {
"lint": "eslint -f json -o gl-codequality.json .",
},
}

En vez de enchufarlo en junit vamos a enchufarlo en codequality. Este tipo de test es del tipo codequality que analizaremos más adelante.

lint-test:
stage: test
image: node:22-slim
script:
- npm ci
- npm run lint # Esto llamará el comando original
artifacts:
when: always
expire_in: "3 months"
reports:
codequality: gl-codequality.json # publicaremos aquí.
git add .gitlab-ci.yml
git add packages.json
git commit -m "add reports to linter"
git push origin pipe/reports

La visión ya está en el propio push o merge que generó el code quality y no en la misma pestaña que están los tests unitarios.

Si declaramos una variable cualquiera que nunca fue utilizada romperá el pipeline en el linter, entonces podemos probar.

describe('App', () => {
it('renders the App component', () => {
render(<App />)
const textElement = screen.getByText(/Learn GitLab/i);
let myNewVar; // añadido
expect(textElement).toBeInTheDocument();

//screen.debug(); // imprime el jsx en el componente App en la línea de comandos
})

En este caso, GitLab guarda los artifacts de cada pipeline (como el gl-codequality.json).

A la hora de abrir un Merge Request, intenta comparar el report actual con el de la branch base (ej: main) del último pipeline válido que aún tiene artifact.

Si el artifact expiró, ya no tiene con qué comparar asume que "no cambió nada" o ignora el análisis. Por eso es bueno que guardemos los reports por un tiempo mayor.

¿Y en cuanto al job vulnerability-test, qué podemos hacer con el reports?

vulnerability-test:
stage: test # mismo stage
image: node:22-slim
script:
- npm ci
- npm audit --audit-level=high --json > vulnerability-report.json
artifacts:
when: on_failure
expire_in: "1 hour"
paths:
- vulnerability-report.json

Antes de hacer eso vamos a estudiar un poco de reports.

Reports

Para ayudar, un poco de documentación oficial de reports.

Primero vamos a conocer los tipos de reports que existen en el momento.

  • accessibility: Análisis automático para detectar problemas de usabilidad e inclusión digital en interfaces web. Prueba cosas como: uso correcto de alt en imágenes, contraste entre texto y fondo, navegabilidad con teclado, presencia de labels en inputs, estructura semántica (headings, landmarks, etc)

  • annotations:

  • api_fuzzing: Probar APIs mandando datos aleatorios, inesperados o maliciosos para intentar romper, bloquear o explotar la aplicación.

  • browser_performance: Informe automático de rendimiento de una página web, enfocado en la experiencia del usuario (UX). Prueba cosas como: tiempo hasta el primer contenido visible (First Contentful Paint), tiempo hasta que la página sea interactiva (Time to Interactive), frames por segundo, uso de CPU/memoria, carga de scripts/pesos de recursos. GitLab usa Sitespeed.io, que ejecuta tests con Chrome en background vía Puppeteer. Este test sólo tiene sentido después del deploy, por ejemplo en el entorno de staging o develop.

  • coverage_report: porcentaje de líneas/funciones/bloques probados en tu código. Vamos a implementar.

  • codequality

  • container_scanning

  • coverage_fuzzing

  • cyclonedx: Un formato estandarizado para describir todo lo que tu app usa (libs, paquetes, versiones, etc), con enfoque en seguridad y compliance.

  • dast

  • dependency_scanning

  • dotenv

  • junit

  • load_performance

  • metrics

  • requirements

  • sast

  • secret_detection

  • terraform

GitLab entiende varios tipos de reports para mostrar resultados visuales bonitos en las MRs, pipelines y Security Dashboards.

Cada tipo tiene su formato JSON específico.

coverage_report

Para implementar el test de cobertura en el proyecto vamos a alterar lo siguiente en el archivo vite.config.js y añadir el bloque abajo.


environment: "jsdom",
setupFiles: "./tests/setup.js",
exclude: ["**/node_modules/**", "**/dist/**", "**/e2e/**"],
reporters: ["verbose", "junit", "html"],
coverage: { ## El bloque coverage
provider: "istanbul",
reporter: ["text", "json", "html", "cobertura"],
},
outputFile: {
junit: "./reports/junit.xml",
html: "./reports/html/index.html",
}

Y en package.json vamos a añadir en scripts

  "scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest",
"e2e": "npx playwright test",
"lint": "eslint --format gitlab .",
"preview": "vite preview",
"coverage": "vitest run --coverage" //Esta línea
},

Añade en .gitignore la carpeta coverage si no subirá la carpeta de local.

echo "coverage" >> .gitignore

Para hacer el test localmente ejecuta.

npm test -- --coverage

# Removido parte para facilitar la lectura

Test Files 1 passed (1)
Tests 3 passed (3)
Start at 07:18:28
Duration 8.09s (transform 83ms, setup 168ms, collect 83ms, tests 27ms, environment 405ms, prepare 48ms)

% Coverage report from istanbul
--------------------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------------------------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0.02 | 2.22 |
learn-gitlab-app | 0 | 0 | 100 | 0 |
playwright.config.cjs | 0 | 0 | 100 | 0 | 2-13
learn-gitlab-app/build/assets | 0 | 0 | 0 | 0 |
index-BcKvuBhg.js | 0 | 0 | 0 | 0 | 1-40
learn-gitlab-app/reports/html/assets | 0 | 0 | 0 | 0 |
index-Cv3XDLXs.js | 0 | 0 | 0 | 0 | 1-52
learn-gitlab-app/src | 50 | 100 | 100 | 50 |
App.jsx | 100 | 100 | 100 | 100 |
main.jsx | 0 | 100 | 100 | 0 | 6
--------------------------------------|---------|----------|---------|---------|-------------------

Al ejecutar ese test, todo estará dentro de la carpeta coverage y el archivo que nos interesa es el cobertura-coverage.xml que es un formato que GitLab entiende.

Ahora queremos que esto esté en el report entonces vamos a añadir un job más en el stage test dentro de .gitlab-ci.yml.

coverage-test:
stage: test
image: node:22-slim
script:
- npm ci
- npm test -- --coverage
artifacts:
when: always
expire_in: "1 hour"
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml

Durante el aprendizaje vamos comprobando más tests, no te preocupes ahora por eso, lo importante es conocer las cosas y saber lo que podemos hacer.

Code Quality Report (codequality)

El Code Quality Report en GitLab muestra directamente en el Merge Request todos los problemas encontrados en el código, como:

Por eso no conseguimos ver lo que hicimos en el linter, pues no estábamos en un merge request. Haremos eso más adelante.

  • Código duplicado
  • Malas prácticas
  • Violación de estilo
  • Bugs potenciales (tipo await perdido)

Ayuda a automatizar revisión de código y forzar calidad mínima en el pipeline CI/CD.

GitLab espera un archivo JSON específico, con cada problema descrito en una estructura estandarizada.

No es cualquier JSON: tiene que seguir el GitLab CodeQuality Schema correctamente! No vamos a parar para ver ese schema, deja que las herramientas y quienes las desarrollan lo hagan. Por eso pasamos --format gitlab anteriormente.

Varias herramientas hacen eso, lo que necesitamos es saber cómo crear archivo json en el formato correcto.

  • Lint / Code Quality: ESLint, Stylelint, Pylint, Flake8, GolangCI-Lint, Rubocop, PHP_CodeSniffer, SwiftLint, ktlint, TFLint, Dockerfilelint, Hadolint, ShellCheck, markdownlint

Seguridad (SAST / Static Analysis): Bandit, Brakeman, Semgrep, ESLint-plugin-security, Gosec, NodeJsScan, Safety, Trivy

Análisis Profundo / Code Smells: SonarQube, SonarCloud, CodeClimate, DeepSource, Codacy

IaC / Cloud / Containers: KubeLinter, Checkov, TFSec, CFN-Nag, Conftest

Licenciamiento / Vulnerabilidades de Dependencias: npm audit, yarn audit, Snyk, OWASP Dependency-Check

artifacts:
reports:
codequality: path/to/report.json

SAST Report (sast)

Static Application Security Testing (vulnerabilidades de código).

Usado en el Security Dashboard.

Ejemplo: Trivy, GitLab SAST scanners (Node.js, Python, etc).

artifacts:
reports:
sast: path/to/sast-report.json

Dependency Scanning (dependency_scanning)

Escanea dependencias (package.json, pom.xml...) por CVEs.

Es tipo npm audit, pero compatible con GitLab Security.

artifacts:
reports:
dependency_scanning: path/to/report.json

Container Scanning (container_scanning)

Busca vulnerabilidades en imágenes Docker.

Usa scanners tipo Trivy, Grype, Clair.

Artifacts:

artifacts:
reports:
container_scanning: path/to/report.json

DAST Report (dast)

Dynamic Application Security Testing.

Escanea la app ejecutándose (no el código).

Ejemplo: OWASP ZAP.

artifacts:
reports:
dast: path/to/report.json

Terraform Reports (terraform)

Muestra cambios de infraestructura detectados en Terraform.

Infraestructura como código visible en las MRs.

artifacts:
reports:
terraform: path/to/terraform-report.json

Consejo

Si observaste bien todos los tests aquí fueron ejecutados en paralelo si uno falla romperá el stage test. Hicimos eso para ganar velocidad. No existe un orden de ejecución. Cuidado con jobs que se ejecutan en paralelo que a veces queda más complicado depurar dónde ocurrió el problema.