Compartir comentarios
Las respuestas se generan en base a la documentación.

Ejecutar pruebas de Node.js en un contenedor

Requisitos previos

Completa todas las secciones anteriores de esta guía, comenzando con Contenedorizar una aplicación de Node.js.

Descripción general

Las pruebas son una parte fundamental para crear software confiable. Ya sea que escribas pruebas unitarias, de integración o de extremo a extremo (end-to-end), ejecutarlas de manera consistente en diferentes entornos es muy importante. Docker facilita esto al brindarte la misma configuración localmente, en CI/CD y durante la construcción de la imagen.

Ejecutar pruebas al desarrollar localmente

La aplicación de ejemplo utiliza Vitest para las pruebas y ya incluye pruebas para componentes de React, hooks personalizados, rutas de API, operaciones de base de datos y funciones de utilidad.

Ejecutar pruebas localmente (sin Docker)

$ npm run test

Agregar el servicio de pruebas a Docker Compose

Para ejecutar pruebas en un entorno contenedorizado, necesitas agregar un servicio de pruebas dedicado a tu archivo compose.yml. Agrega la siguiente configuración de servicio:

services:
  # ... servicios existentes ...

  # ========================================
  # Servicio de pruebas
  # ========================================
  app-test:
    build:
      context: .
      dockerfile: Dockerfile
      target: test
    container_name: todoapp-test
    environment:
      NODE_ENV: test
      POSTGRES_HOST: db
      POSTGRES_PORT: 5432
      POSTGRES_DB: todoapp_test
      POSTGRES_USER: todoapp
      POSTGRES_PASSWORD: '${POSTGRES_PASSWORD:-todoapp_password}'
    depends_on:
      db:
        condition: service_healthy
    command: ['npm', 'run', 'test:coverage']
    networks:
      - todoapp-network
    profiles:
      - test

Esta configuración del servicio de pruebas:

  • Se construye desde la etapa de pruebas: Utiliza el objetivo (target) test de tu Dockerfile multietapa.
  • Base de datos de pruebas aislada: Utiliza una base de datos todoapp_test independiente para las pruebas.
  • Basado en perfiles: Utiliza el perfil test para que solo se ejecute cuando se solicite explícitamente.
  • Dependencia de estado de salud: Espera a que la base de datos esté saludable (healthy) antes de iniciar las pruebas.

Ejecutar pruebas en un contenedor

Puedes ejecutar las pruebas utilizando el servicio de pruebas dedicado:

$ docker compose up app-test --build

O ejecutar las pruebas en el servicio de desarrollo:

$ docker compose run --rm app-dev npm run test

Para una ejecución única de pruebas con cobertura:

$ docker compose run --rm app-dev npm run test:coverage

Ejecutar pruebas con cobertura

Para generar un informe de cobertura:

$ npm run test:coverage

Deberías ver una salida como la siguiente:

> [email protected] test
> vitest --run

 ✓ src/server/__tests__/routes/todos.test.ts (5 tests) 16ms
 ✓ src/shared/utils/__tests__/validation.test.ts (15 tests) 6ms
 ✓ src/client/components/__tests__/LoadingSpinner.test.tsx (8 tests) 67ms
 ✓ src/server/database/__tests__/postgres.test.ts (13 tests) 136ms
 ✓ src/client/components/__tests__/ErrorMessage.test.tsx (8 tests) 127ms
 ✓ src/client/components/__tests__/TodoList.test.tsx (8 tests) 147ms
 ✓ src/client/components/__tests__/TodoItem.test.tsx (8 tests) 218ms
 ✓ src/client/__tests__/App.test.tsx (13 tests) 259ms
 ✓ src/client/components/__tests__/AddTodoForm.test.tsx (12 tests) 323ms
 ✓ src/client/hooks/__tests__/useTodos.test.ts (11 tests) 569ms

 Test Files  9 passed (9)
      Tests  88 passed (88)
    Start at  20:57:19
    Duration  4.41s (transform 1.79s, setup 2.66s, collect 5.38s, tests 4.61s, environment 14.07s, prepare 4.34s)

Estructura de las pruebas

La suite de pruebas cubre:

  • Componentes del cliente (src/client/components/__tests__/): Pruebas de componentes de React con React Testing Library.
  • Hooks personalizados (src/client/hooks/__tests__/): Pruebas de hooks de React con simulaciones (mocking) adecuadas.
  • Rutas del servidor (src/server/__tests__/routes/): Pruebas de puntos de enlace (endpoints) de la API.
  • Capa de base de datos (src/server/database/__tests__/): Pruebas de operaciones de base de datos PostgreSQL.
  • Funciones de utilidad (src/shared/utils/__tests__/): Pruebas de validación y funciones auxiliares.
  • Pruebas de integración (src/client/__tests__/): Pruebas de integración de toda la aplicación.

Ejecutar pruebas al construir

Para ejecutar pruebas durante el proceso de construcción de Docker, necesitas agregar una etapa de pruebas dedicada a tu Dockerfile. Si aún no has agregado esta etapa, añade lo siguiente a tu Dockerfile multietapa:

# ========================================
# Etapa de pruebas
# ========================================
FROM build-deps AS test

# Configurar el entorno
ENV NODE_ENV=test \
    CI=true

# Copiar archivos fuente
COPY --chown=nodejs:nodejs . .

# Cambiar a usuario no root
USER nodejs

# Ejecutar pruebas con cobertura
CMD ["npm", "run", "test:coverage"]

Esta etapa de pruebas:

  • Entorno de pruebas: Configura NODE_ENV=test y CI=true para una correcta ejecución de las pruebas.
  • Usuario no root: Ejecuta las pruebas como el usuario nodejs por seguridad.
  • Ejecución flexible: Utiliza CMD en lugar de RUN para permitir la ejecución de pruebas durante la construcción o como un contenedor independiente.
  • Soporte de cobertura: Configurado para ejecutar pruebas con informes de cobertura.

Construir y ejecutar pruebas durante la construcción de la imagen

Para construir una imagen que ejecute las pruebas durante el proceso de construcción, puedes crear un Dockerfile personalizado o modificar temporalmente el existente:

$ docker build --target test -t node-docker-image-test .

Ejecutar pruebas en un contenedor de pruebas dedicado

El enfoque recomendado es utilizar el servicio de pruebas definido en compose.yml:

$ docker compose --profile test up app-test --build

O ejecutarlo como un contenedor de un solo uso:

$ docker compose run --rm app-test

Ejecutar pruebas con cobertura en CI/CD

Para la integración continua, puedes ejecutar las pruebas con cobertura:

$ docker build --target test --progress=plain --no-cache -t test-image .
$ docker run --rm test-image npm run test:coverage

Deberías ver una salida que contenga lo siguiente:

 ✓ src/server/__tests__/routes/todos.test.ts (5 tests) 16ms
 ✓ src/shared/utils/__tests__/validation.test.ts (15 tests) 6ms
 ✓ src/client/components/__tests__/LoadingSpinner.test.tsx (8 tests) 67ms
 ✓ src/server/database/__tests__/postgres.test.ts (13 tests) 136ms
 ✓ src/client/components/__tests__/ErrorMessage.test.tsx (8 tests) 127ms
 ✓ src/client/components/__tests__/TodoList.test.tsx (8 tests) 147ms
 ✓ src/client/components/__tests__/TodoItem.test.tsx (8 tests) 218ms
 ✓ src/client/__tests__/App.test.tsx (13 tests) 259ms
 ✓ src/client/components/__tests__/AddTodoForm.test.tsx (12 tests) 323ms
 ✓ src/client/hooks/__tests__/useTodos.test.ts (11 tests) 569ms

 Test Files  9 passed (9)
      Tests  88 passed (88)
    Start at  20:57:19
    Duration  4.41s (transform 1.79s, setup 2.66s, collect 5.38s, tests 4.61s, environment 14.07s, prepare 4.34s)

Resumen

En esta sección, aprendiste cómo ejecutar pruebas al desarrollar localmente usando Docker Compose y cómo ejecutar pruebas al construir tu imagen.

Información relacionada:

Pasos siguientes

A continuación, aprenderás cómo configurar un pipeline de CI/CD utilizando GitHub Actions.