Pipelines do GitLab CI para Playwright exigem uma decisão de design antecipada: instalar os navegadores durante o pipeline ou usar a imagem Docker oficial do Playwright. A abordagem com Docker é mais rápida. Ela evita o modo de falha mais comum: uma incompatibilidade de versão entre a tag da imagem e o @playwright/test no package.json quebra o pipeline com um erro executable doesn't exist.

Pré-requisitos

  • Projeto Playwright funcionando localmente com npx playwright test
  • Repositório no GitLab (gitlab.com ou self-hosted)
  • .gitlab-ci.yml ainda não existe (ou você está adicionando a ele)

O pipeline mínimo funcional

Crie .gitlab-ci.yml na raiz do projeto:

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

É isso. Faça push desse arquivo e o GitLab CI vai rodar seus testes em cada commit.

Explicação linha a linha

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

Esse é o container Docker dentro do qual o pipeline roda. A imagem Docker oficial do Playwright vem com:

  • Node.js
  • Todas as dependências de navegadores do Playwright pré-instaladas
  • Ambiente Linux

Essa é a abordagem recomendada: sem instalação de navegador necessária no pipeline.

Fixe a versão (v1.44.0, não latest) para que o pipeline não quebre quando o Playwright lançar uma nova versão. Atualize manualmente quando fizer upgrade do Playwright localmente.

npm ci vs. npm install

No CI, sempre use npm ci em vez de npm install:

  • npm ci instala exatamente o que está no package-lock.json (determinístico)
  • npm ci é mais rápido em ambientes de CI
  • npm ci falha se o package-lock.json estiver ausente ou inconsistente

artifacts

O Playwright gera um relatório HTML em playwright-report/ após cada execução. A seção artifacts diz ao GitLab para salvar essa pasta para você poder baixar e visualizar.

  • when: always — salva artefatos mesmo se os testes falharem (você mais precisa do relatório quando os testes falham!)
  • expire_in: 7 days — o GitLab deleta artefatos automaticamente após 7 dias

Para ver o relatório: GitLab CI → o pipeline → o job → "Download artifacts" → abra playwright-report/index.html.

Um pipeline mais completo

Para projetos reais, você vai querer mais estrutura:

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

stages:
  - test

variables:
  # Armazenar node_modules em cache entre runs para velocidade
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

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

playwright-tests:
  stage: test
  
  # Rodar em merge requests e na branch main
  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 para o job inteiro
  timeout: 20 minutes

O que há de novo aqui:

variables: Define variáveis de ambiente para o job. npm_config_cache diz ao npm para usar um diretório de cache específico. cache: Os módulos Node são armazenados em cache entre runs do pipeline. Primeiro run: lento (baixa tudo). Runs subsequentes: rápido (lê do cache). A chave é o nome da branch, então branches diferentes têm caches separados. rules: Controla quando esse job roda. A configuração acima roda em:
  • Merge requests (para ver os resultados antes de fazer merge)
  • Pushes para main (após fazer merge)
--reporter=html,junit: Gera tanto o relatório HTML quanto o XML JUnit. O formato JUnit é entendido pelo GitLab e mostra os resultados dos testes diretamente na UI do pipeline. reports: junit: Diz ao GitLab onde está o XML JUnit. O GitLab então mostra uma aba "Tests" no pipeline com passou/falhou por teste.

Usando variáveis de ambiente (segredos)

Nunca coloque senhas ou chaves de API no .gitlab-ci.yml. Use variáveis CI/CD do GitLab:

Definindo variáveis no GitLab:

1. Project → Settings → CI/CD → Variables

2. Adicione: BASE_URL, ADMIN_EMAIL, ADMIN_PASSWORD, API_KEY

3. Marque as sensíveis como "Masked" (ocultas nos logs)

4. Marque as específicas de ambiente como "Protected" (só roda em branches protegidas)

Usando no pipeline:

playwright-tests:
  script:
    - npm ci
    - npx playwright test
  variables:
    BASE_URL: $BASE_URL              # Das variáveis CI do GitLab
    ADMIN_EMAIL: $ADMIN_EMAIL        # Das variáveis CI do GitLab

Usando no config do Playwright:

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

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

Variáveis CI do GitLab estão disponíveis como variáveis de ambiente no job: process.env.BASE_URL funciona.

Execução paralela e sharding

Para suites de testes grandes, rode os testes em 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

Isso cria 4 jobs paralelos, cada um rodando 25% dos testes. O tempo total de testes é dividido por 4.

Atenção: juntar os relatórios HTML divididos exige steps adicionais (o comando merge-reports do Playwright).

Rodando em modo headed (debugging)

Por padrão, o Playwright roda headless no CI. Se precisar debugar visualmente:

playwright-debug:
  stage: test
  script:
    - npm ci
    - npx playwright test --headed --video=on
  when: manual  # Só roda quando disparado manualmente
  artifacts:
    when: always
    paths:
      - test-results/  # Vídeos são salvos aqui
    expire_in: 1 day

when: manual significa que esse job não roda automaticamente: você o dispara manualmente pela UI do GitLab quando precisar debugar.

Lidando com testes flaky

O Playwright tem lógica de retry integrada. Configure para CI:

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

Ou no .gitlab-ci.yml, permita que o próprio job tente novamente em caso de falha:

playwright-tests:
  retry:
    max: 1  # Tenta novamente o job inteiro uma vez se falhar
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

Retry no nível do job (GitLab) é para falhas de infraestrutura. Retry no nível de teste (config do Playwright) é para testes flaky. Use os dois.

Exemplo completo com múltiplos ambientes

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.seuapp.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

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

Isso roda os testes de staging na branch develop e nos PRs, e os testes de produção apenas ao fazer merge na main.

Resolvendo problemas comuns

Erro "Executable doesn't exist":

Você não está usando a imagem Docker do Playwright, ou está na versão errada. Use mcr.microsoft.com/playwright:v1.44.0-jammy e a versão deve corresponder exatamente à sua versão do @playwright/test.

Testes atingem timeout no CI mas passam localmente:

Máquinas de CI são mais lentas. Aumente os timeouts no playwright.config.ts:

export default defineConfig({
  timeout: 60000,        // 60s por teste (acima do padrão de 30s)
  actionTimeout: 15000,  // 15s por ação
});

"Cannot find module" no CI:

Você tem uma dependência que não está no package.json. Rode npm install localmente e faça commit do package.json e package-lock.json atualizados.

Pipeline lento por causa do npm install:

Adicione cache (mostrado no exemplo completo acima). O primeiro run vai ser lento; os runs seguintes vão ser rápidos.

Checklist rápido

Antes de fazer push do seu primeiro pipeline:

  • [ ] .gitlab-ci.yml está na raiz do projeto
  • [ ] Usando a imagem Docker do Playwright com versão fixada
  • [ ] npm ci (não npm install)
  • [ ] Artefatos configurados para salvar playwright-report/
  • [ ] Segredos nas variáveis CI do GitLab, não no arquivo YAML
  • [ ] retries do Playwright configurado para o ambiente de CI
  • [ ] timeout definido no playwright.config.ts (máquinas de CI são mais lentas)
→ Veja também: CI/CD para QA: GitHub Actions, Jenkins e GitLab Comparados | GitHub Actions para Testes Playwright: A Configuração Completa (2026) | Arquivo de Configuração do Playwright Explicado: Todas as Opções

Com esse setup, cada push para o repositório vai rodar automaticamente a suite de testes e disponibilizar os resultados na visualização do pipeline do GitLab.