Los pipelines de GitLab CI para Playwright requieren una decisión de diseño desde el principio: instalar los navegadores durante el pipeline o usar la imagen Docker oficial de Playwright. La imagen Docker es más rápida y evita el fallo más común, donde una incompatibilidad de versión entre el tag de la imagen y @playwright/test en package.json rompe el pipeline con un error executable doesn't exist. Esta guía cubre el .gitlab-ci.yml mínimo que funciona, la subida de artefactos, los secretos, el caché, el sharding paralelo y una configuración multi-entorno para staging y producción.

Prerequisitos

Necesitas un proyecto de Playwright funcionando localmente con npx playwright test, un repositorio en GitLab (gitlab.com o autoalojado), y un .gitlab-ci.yml que aún no existe o que estás ampliando.

El pipeline mínimo que funciona

Crea .gitlab-ci.yml en la raíz del proyecto:

image: mcr.microsoft.com/playwright:v1.44.0-jammy

stages:
  - test

playwright-tests:
  stage: test
  script:
    - npm ci
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
    expire_in: 7 days

Sube este archivo y GitLab CI ejecutará los tests en cada commit.

Qué hace cada parte

image: mcr.microsoft.com/playwright:v1.44.0-jammy

Este es el contenedor Docker donde corre el pipeline. La imagen oficial de Playwright ya incluye Node.js, todas las dependencias del sistema para los navegadores y un entorno Linux.

El enfoque recomendado es este: sin instalación de navegadores en el pipeline.

Pinea la versión (v1.44.0, no latest) para que el pipeline no se rompa cuando Playwright publique una nueva versión. Actualízala manualmente cuando actualices Playwright en local.

npm ci vs. npm install

En CI usa siempre npm ci en lugar de npm install: instala exactamente lo que está en package-lock.json (determinista), es más rápido en entornos CI, y falla si package-lock.json no existe o es inconsistente.

artifacts

Playwright genera un reporte HTML en playwright-report/ después de cada ejecución. La sección artifacts le dice a GitLab que guarde esa carpeta para que puedas descargarla y verla.

when: always guarda los artefactos aunque los tests fallen, porque el reporte es más valioso precisamente cuando algo falla. expire_in: 7 days hace que GitLab elimine los artefactos automáticamente a los 7 días.

Para ver el reporte: GitLab CI → el pipeline → el job → "Download artifacts" → abre playwright-report/index.html.

Un pipeline más completo

Para proyectos reales, se necesita más estructura:

image: mcr.microsoft.com/playwright:v1.44.0-jammy

stages:
  - test

variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

cache:
  key: "$CI_COMMIT_REF_SLUG"
  paths:
    - .npm/
    - node_modules/

playwright-tests:
  stage: test

  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

  script:
    - npm ci
    - npx playwright test --reporter=html,junit

  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    reports:
      junit: test-results/results.xml
    expire_in: 7 days

  timeout: 20 minutes

variables: define variables de entorno para el job. npm_config_cache le dice a npm qué directorio de caché usar. cache: los módulos de Node se almacenan en caché entre ejecuciones del pipeline. La primera vez es lenta. Las siguientes son rápidas. La clave es el nombre de rama, así cada rama tiene su propio caché. rules: controla cuándo se ejecuta el job. La configuración de arriba corre en merge requests (para ver los resultados antes de mergear) y en pushes a main (después de mergear). --reporter=html,junit: genera el reporte HTML y el XML de JUnit. GitLab entiende el formato JUnit y muestra los resultados directamente en la UI del pipeline. reports: junit: le indica a GitLab dónde está el XML de JUnit. GitLab muestra entonces una pestaña "Tests" en el pipeline con el estado de cada test.

Variables de entorno y secretos

Nunca pongas contraseñas ni claves de API en .gitlab-ci.yml. Usa las variables de CI/CD de GitLab:

Cómo configurarlas en GitLab

1. Project → Settings → CI/CD → Variables

2. Agrega: BASE_URL, ADMIN_EMAIL, ADMIN_PASSWORD, API_KEY

3. Marca las sensibles como "Masked" (no se muestran en los logs)

4. Marca las de entornos específicos como "Protected" (solo corren en ramas protegidas)

Cómo usarlas en el pipeline

playwright-tests:
  script:
    - npm ci
    - npx playwright test
  variables:
    BASE_URL: $BASE_URL
    ADMIN_EMAIL: $ADMIN_EMAIL

Cómo usarlas en la config de Playwright

// playwright.config.ts
import dotenv from 'dotenv';
dotenv.config();

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
  },
});

Las variables de CI/CD de GitLab están disponibles como variables de entorno en el job. process.env.BASE_URL funciona sin configuración adicional.

Ejecución paralela y sharding

Para suites grandes, ejecuta los tests en paralelo:

playwright-tests:
  stage: test

  parallel:
    matrix:
      - SHARD: ["1/4", "2/4", "3/4", "4/4"]

  script:
    - npm ci
    - npx playwright test --shard=$SHARD

  artifacts:
    when: always
    paths:
      - playwright-report/
    expire_in: 7 days

Esto crea 4 jobs paralelos, cada uno ejecutando el 25% de los tests. El tiempo total se divide aproximadamente por 4.

Para combinar los reportes HTML divididos necesitas el comando merge-reports de Playwright como paso adicional.

Modo headed para depuración

Por defecto, Playwright corre en modo headless en CI. Para depurar visualmente:

playwright-debug:
  stage: test
  script:
    - npm ci
    - npx playwright test --headed --video=on
  when: manual
  artifacts:
    when: always
    paths:
      - test-results/
    expire_in: 1 day

when: manual significa que el job no corre automáticamente. Lo activas desde la UI de GitLab cuando necesitas depurar.

Tests con resultados inestables

Playwright tiene lógica de reintentos integrada. Configúrala para CI:

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,
});

O en .gitlab-ci.yml, permitir que el job mismo reintente en caso de fallo:

playwright-tests:
  retry:
    max: 1
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

El retry a nivel de job (GitLab) es para fallos de infraestructura. El retry a nivel de test (config de Playwright) es para tests inestables. Los dos tienen su lugar.

Configuración con múltiples entornos

image: mcr.microsoft.com/playwright:v1.44.0-jammy

stages:
  - test

.playwright-base:
  script:
    - npm ci
    - npx playwright test --reporter=html,junit
  artifacts:
    when: always
    paths:
      - playwright-report/
    reports:
      junit: test-results/results.xml
    expire_in: 7 days
  timeout: 20 minutes

playwright-staging:
  extends: .playwright-base
  variables:
    BASE_URL: https://staging.tuapp.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

playwright-production:
  extends: .playwright-base
  variables:
    BASE_URL: https://tuapp.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  environment:
    name: production

Los tests de staging corren en la rama develop y en los merge requests. Los de producción solo cuando se mergea a main.

Problemas comunes y cómo resolverlos

Error "Executable doesn't exist"

No estás usando la imagen Docker de Playwright, o la versión no coincide. Usa mcr.microsoft.com/playwright:v1.44.0-jammy y asegúrate de que la versión sea exactamente la misma que @playwright/test en package.json.

Los tests tienen timeout en CI pero pasan en local

Las máquinas de CI son más lentas. Aumenta los timeouts en playwright.config.ts:

export default defineConfig({
  timeout: 60000,
  actionTimeout: 15000,
});

"Cannot find module" en CI

Hay una dependencia que no está en package.json. Ejecuta npm install en local y confirma el package.json y package-lock.json actualizados.

Pipeline lento por la instalación de npm

Agrega caché (como en el ejemplo completo de arriba). La primera ejecución será lenta; las siguientes serán rápidas.

Checklist antes del primer push

  • [ ] .gitlab-ci.yml está en la raíz del proyecto
  • [ ] Se usa la imagen Docker de Playwright con versión pinada
  • [ ] npm ci (no npm install)
  • [ ] Artefactos configurados para guardar playwright-report/
  • [ ] Los secretos están en variables de CI/CD de GitLab, no en el archivo YAML
  • [ ] retries de Playwright configurado para el entorno CI
  • [ ] timeout definido en playwright.config.ts
→ See also: CI/CD para QA: GitHub Actions, Jenkins y GitLab Comparados | GitHub Actions para Tests de Playwright: La Configuración Completa (2026) | Archivo de Configuración de Playwright Explicado: Todas las Opciones