Пайплайны GitLab CI для Playwright требуют одного дизайнерского решения с самого начала: устанавливать браузеры во время пайплайна или использовать официальный Docker-образ Playwright. Вариант с Docker-образом быстрее и избавляет от самой частой причины отказа: несовпадения версий между тегом образа и @playwright/test в package.json, из-за которого пайплайн падает с ошибкой executable doesn't exist. В этом гайде: минимальный рабочий .gitlab-ci.yml, загрузка артефактов, секреты, кэширование, параллельное шардирование и мультиокружная настройка для staging и production.

Предварительные требования

  • Playwright-проект работает локально через npx playwright test
  • Репозиторий GitLab (gitlab.com или self-hosted)
  • .gitlab-ci.yml ещё не существует (или добавляешь в него)

Минимальный рабочий пайплайн

Создаёшь .gitlab-ci.yml в корне проекта:

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

Всё. Пушишь этот файл и GitLab CI запускает тесты на каждый коммит.

Разберём что делает каждая часть.

Объяснение строка за строкой

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

Docker-контейнер внутри которого выполняется пайплайн. Официальный Docker-образ Playwright включает Node.js, все предустановленные зависимости браузеров и Linux-окружение.

Это рекомендуемый подход: установка браузеров в пайплайне не нужна.

Фиксируй версию (v1.44.0, не latest) чтобы пайплайн не ломался при выходе новой версии Playwright. Обновляй вручную когда обновляешь Playwright локально.

npm ci vs. npm install

В CI всегда используй npm ci вместо npm install: npm ci устанавливает ровно то что в package-lock.json (детерминировано), работает быстрее в CI-окружениях и падает если package-lock.json отсутствует или не согласован.

artifacts

Playwright генерирует HTML-отчёт в playwright-report/ после каждого запуска. Секция artifacts говорит GitLab сохранить эту папку чтобы её можно было скачать и просмотреть.

when: always сохраняет артефакты даже при падении тестов: отчёт нужен именно когда тесты упали. expire_in: 7 days говорит GitLab автоматически удалять артефакты через 7 дней.

Просмотр отчёта: GitLab CI → пайплайн → джоба → «Download artifacts» → открываешь playwright-report/index.html.

Более полный пайплайн

Для реальных проектов нужна бо́льшая структура:

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

stages:
  - test

variables:
  # Кэш node_modules между запусками для скорости
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

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

playwright-tests:
  stage: test
  
  # Запуск на merge request-ах и основной ветке
  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: переменные окружения для джобы. npm_config_cache говорит npm использовать конкретную директорию кэша. cache: Node-модули кэшируются между запусками пайплайна. Первый запуск медленный (скачивает всё). Последующие быстрые (читает из кэша). Ключ: имя ветки, у разных веток отдельные кэши. rules: контролирует когда запускается джоба. Конфиг выше запускается на merge request-ах (видишь результаты тестов до мёрджа) и на пушах в main (после мёрджа). --reporter=html,junit: генерирует и HTML-отчёт, и JUnit XML. Формат JUnit понимает GitLab и отображает результаты тестов прямо в UI пайплайна. reports: junit: говорит GitLab где находится JUnit XML. GitLab показывает вкладку «Tests» в пайплайне с pass/fail по каждому тесту.

Использование переменных окружения (секреты)

Никогда не помещай пароли или API-ключи в .gitlab-ci.yml. Используй переменные GitLab CI/CD:

Настройка переменных в GitLab

1. Project → Settings → CI/CD → Variables

2. Добавляешь: BASE_URL, ADMIN_EMAIL, ADMIN_PASSWORD, API_KEY

3. Чувствительные помечаешь как «Masked» (скрыты в логах)

4. Специфичные для окружения помечаешь как «Protected» (только на защищённых ветках)

Использование в пайплайне

playwright-tests:
  script:
    - npm ci
    - npx playwright test
  variables:
    BASE_URL: $BASE_URL              # Из переменных GitLab CI
    ADMIN_EMAIL: $ADMIN_EMAIL        # Из переменных GitLab CI

Использование в конфиге Playwright

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

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

Переменные GitLab CI доступны как переменные окружения в джобе: process.env.BASE_URL работает.

Параллельное выполнение и шардирование

Для больших тест-сьютов запускаешь тесты параллельно:

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

Создаётся 4 параллельных джобы, каждая запускает 25% тестов. Общее время тестирования делится примерно на 4.

Объединение разбитых HTML-отчётов требует дополнительных шагов (команда merge-reports в Playwright).

Запуск в headed-режиме (для отладки)

По умолчанию Playwright запускается headless в CI. Если нужна визуальная отладка:

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 означает: джоба не запускается автоматически, запускаешь её вручную из UI GitLab когда нужна отладка.

Работа с флакующими тестами

Playwright имеет встроенную логику повторных попыток. Настройка для CI:

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,  // 2 повтора только в CI
});

Или в .gitlab-ci.yml разрешить самой джобе повторяться при падении:

playwright-tests:
  retry:
    max: 1  # Повторить всю джобу один раз при падении
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

Повтор на уровне джобы (GitLab) предназначен для инфраструктурных сбоев. Повтор на уровне теста (конфиг Playwright) для флакующих тестов. Используй оба.

Полный пример с несколькими окружениями

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

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

Staging-тесты запускаются на ветке develop и MR-ах, production-тесты только при мёрдже в main.

Диагностика частых проблем

Ошибка «Executable doesn't exist»

Не используешь Docker-образ Playwright или версия не та. Держись mcr.microsoft.com/playwright:v1.44.0-jammy и версия должна точно совпадать с версией @playwright/test.

Тесты падают по таймауту в CI, но проходят локально

CI-машины медленнее. Увеличивай таймауты в playwright.config.ts:

export default defineConfig({
  timeout: 60000,        // 60с на тест (вместо дефолтных 30с)
  actionTimeout: 15000,  // 15с на действие
});

«Cannot find module» в CI

Зависимость отсутствует в package.json. Запускаешь npm install локально и коммитишь обновлённые package.json и package-lock.json.

Пайплайн медленный из-за npm install

Добавляй кэширование (показано в полном примере выше). Первый запуск медленный, последующие быстрые.

Чеклист перед первым запуском

  • [ ] .gitlab-ci.yml находится в корне проекта
  • [ ] Используется Docker-образ Playwright с зафиксированной версией
  • [ ] npm ci (не npm install)
  • [ ] Артефакты настроены для сохранения playwright-report/
  • [ ] Секреты в переменных GitLab CI, не в YAML-файле
  • [ ] retries в Playwright настроены для CI-окружения
  • [ ] timeout задан в playwright.config.ts (CI-машины медленнее)
→ See also: CI/CD для QA: сравнение GitHub Actions, Jenkins и GitLab | GitHub Actions для тестов Playwright: полная настройка (2026) | Файл конфигурации Playwright: все опции, которые нужно знать

После этой настройки каждый пуш в репозиторий будет автоматически запускать тест-сьют и делать результаты доступными в просмотрщике пайплайна GitLab.