Пропустить --with-deps при установке Playwright в GitHub Actions: самая частая причина, по которой тесты проходят локально и падают в CI. Системные библиотеки вроде libgtk и libnss отсутствуют на чистых Ubuntu-раннерах. Вторая по частоте ошибка: не добавить if: always() к шагу загрузки артефактов. В результате теряешь HTML-отчёт именно тогда, когда тесты упали и он нужен больше всего. В этом гайде: минимальный рабочий воркфлоу, секреты, кэширование браузеров, фильтры веток, матричные кросс-браузерные запуски, шардирование на параллельных джобах и комментарии к PR с результатами тестов.
Почему GitHub Actions
GitHub Actions стал доминирующим CI-инструментом для новых проектов. По данным JetBrains State of CI/CD 2025, его используют 62% разработчиков для личных проектов и 41% в организациях, оба показателя выше чем у любого другого инструмента.
Практические причины просты: бесплатно для публичных репозиториев, 2 000 минут в месяц для приватных, и всё это встроено прямо в GitHub. Не нужно поднимать отдельный сервер, подключать сторонние аккаунты или настраивать вебхуки. Пушишь YAML-файл и тесты запускаются.
Для Playwright GitHub Actions подходит особенно хорошо: Ubuntu-раннеры имеют всё необходимое. Зависимости браузеров, шрифты и системные библиотеки устанавливаются через --with-deps. Команда Playwright тестирует именно на этих раннерах: ты в поддерживаемом окружении.
Минимальный рабочий воркфлоу
Создаёшь файл .github/workflows/playwright.yml в корне проекта. Именно здесь GitHub ищет определения воркфлоу.
mkdir -p .github/workflowsПолный минимальный воркфлоу:
# .github/workflows/playwright.yml
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 14Коммитишь этот файл, пушишь, открываешь вкладку Actions в репозитории на GitHub. Воркфлоу появится и запустится в течение нескольких секунд.
Несколько деталей стоит понять. npm ci вместо npm install устанавливает ровно то что записано в package-lock.json, не изменяя его. Это правильная команда для CI: даёт воспроизводимые сборки. npx playwright install --with-deps устанавливает браузеры вместе с системными зависимостями (libgtk, libnss и прочими) которых нет на чистом Ubuntu-раннере. Именно из-за пропущенного --with-deps Playwright чаще всего падает в CI при успешном прохождении локально.
if: always() на шаге загрузки артефактов критичен. Без него артефакт загружается только при успешном воркфлоу, и ты теряешь отчёт именно тогда, когда тесты упали.
timeout-minutes: 60 на джобе: подстраховка. Зависший тест может израсходовать весь месячный лимит минут прежде чем ты заметишь.
Сохранение и скачивание отчётов
Шаг upload-artifact сохраняет директорию playwright-report/ как скачиваемый zip. После завершения прогона: страница запуска воркфлоу → Summary → Artifacts → playwright-report. Скачиваешь, разархивируешь, открываешь index.html в браузере.
HTML-отчёт показывает какие тесты прошли, какие упали, скриншоты при падениях, трассировки и видео если запись включена. Так исследуешь падения без прямого доступа к CI-раннеру.
Если генерируешь несколько отчётов (по одному на браузер в матричном запуске), давай каждому артефакту уникальное имя:
- name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.browser }}
path: playwright-report/
retention-days: 14retention-days: 14 хранит отчёты две недели: достаточно для большинства сценариев отладки без накопления лишних расходов на хранение. GitHub допускает до 90 дней.
Переменные окружения и секреты
Никогда не помещай учётные данные или URL окружений прямо в YAML-файл воркфлоу. GitHub Secrets: правильное место для всего чувствительного.
Репозиторий → Settings → Secrets and variables → Actions → New repository secret. Добавляешь секреты которые нужны тестам: TEST_USER, TEST_PASSWORD, API-ключи.
Ссылаешься на них в воркфлоу через env: на шаге с тестами:
- name: Run Playwright tests
run: npx playwright test
env:
BASE_URL: https://staging.example.com
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}В тестах читаешь через process.env:
const baseURL = process.env.BASE_URL ?? 'http://localhost:3000';
const user = process.env.TEST_USER ?? '';
const password = process.env.TEST_PASSWORD ?? '';GitHub скрывает значения секретов в логах. Если секрет попадает в вывод, он заменяется на *. Нечувствительные значения вроде BASE_URL можно хранить как переменные репозитория (не секреты): они видны в UI. Переменные для URL и флагов фич, секреты для учётных данных.
pull_request_target, но сначала разберись с последствиями для безопасности.Кэширование для ускорения запусков
Каждый новый запуск воркфлоу устанавливает Node-модули и браузеры Playwright с нуля. На холодном раннере это 2–3 минуты до запуска первого теста. Кэширование существенно сокращает это время.
Экшен setup-node с cache: 'npm' уже обрабатывает кэш node_modules автоматически. Для браузеров Playwright добавляешь отдельный шаг кэширования:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
run: npx playwright install --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'Ключ кэша включает хэш package-lock.json. При обновлении версии Playwright lock-файл меняется, хэш меняется, кэш не попадает в цель, браузеры переустанавливаются. Когда ничего не менялось, кэш срабатывает и установка браузеров пропускается полностью.
На больших сьютах это ощутимо. Сьют из 200 тестов с включённым кэшированием может пройти за 4 минуты вместо 8 только за счёт пропуска повторных загрузок браузеров.
Запуск только на определённых ветках
Секция on: управляет когда воркфлоу запускается. Минимальный пример уже фильтрует по main и develop. Можно конкретизировать:
on:
push:
branches:
- main
- develop
- 'release/**'
pull_request:
branches:
- main
- develop
workflow_dispatch:workflow_dispatch: добавляет кнопку «Run workflow» во вкладке Actions, которая позволяет запускать воркфлоу вручную для конкретной ветки без пуша коммита. Удобно для запуска тестов на конкретной ветке по запросу.
Можно также запускать тесты по расписанию. Ночные smoke-запуски ловят проблемы которые проявляются только в определённые временные окна или после накопления данных:
on:
schedule:
- cron: '0 3 * * *' # 3:00 UTC каждую ночь
push:
branches: [main]
pull_request:
branches: [main]Внутри джобы можно добавлять условия по ветке на конкретные шаги через if::
- name: Run full suite
run: npx playwright test
if: github.ref == 'refs/heads/main'
- name: Run smoke tests only
run: npx playwright test --grep @smoke
if: github.event_name == 'pull_request'Этот паттерн даёт PR-ам быструю обратную связь от smoke-сьюта, а ветка main получает полный прогон.
Матричная стратегия для кросс-браузерного тестирования
Playwright поддерживает Chromium, Firefox и WebKit. Запускать все три на каждом PR дорого по времени и минутам, но кросс-браузерное покрытие нужно. Матричная стратегия запускает параллельные джобы с разными конфигурациями:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ matrix.browser }}-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
run: npx playwright install ${{ matrix.browser }} --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Run tests
run: npx playwright test --project=${{ matrix.browser }}
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Upload report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.browser }}
path: playwright-report/
retention-days: 14fail-fast: false означает: если Firefox упал, джобы Chromium и WebKit продолжают выполняться. При fail-fast: true (дефолт) падение любой матричной джобы отменяет остальные, обычно не то что нужно при отладке кросс-браузерных проблем.
npx playwright install ${{ matrix.browser }} --with-deps устанавливает только браузер для этой джобы, а не все три. Быстрее чем устанавливать всё в каждой джобе.
if: github.ref == 'refs/heads/main' к джобе или используй фильтр ветки в триггере on.push. PR-ы остаются быстрыми; ветка main получает полное покрытие.Шардирование: разбивка тестов по джобам
Шардирование разбивает тест-сьют на несколько параллельных джоб. Матричная стратегия запускает разные конфигурации, шардирование запускает те же тесты быстрее, делением их между джобами:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Run shard
run: npx playwright test --shard=${{ matrix.shard }}/4
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Upload shard report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-shard-${{ matrix.shard }}
path: playwright-report/
retention-days: 14Playwright распределяет тесты равномерно между шардами на основе данных о предыдущих запусках (если предоставлен blob-отчёт) или по порядку файлов. С четырьмя шардами сьют на 20 минут выполняется примерно за 5 минут.
Можно комбинировать шардирование с матричной стратегией. Для больших сьютов распространён паттерн «четыре шарда на браузер»:
strategy:
matrix:
browser: [chromium, firefox]
shard: [1, 2, 3, 4]Это создаёт 8 параллельных джоб. Важно понимать: каждая джоба расходует минуты раннера. 8 джоб по 5 минут стоят 40 минут квоты, столько же сколько последовательный запуск. Выигрыш в реальном времени ожидания, а не в квоте.
Объединение отчётов шардов в один HTML-отчёт требует blob-репортера. Устанавливаешь reporter: 'blob' в конфиге Playwright для CI-запусков, затем добавляешь джобу слияния:
merge-reports:
if: always()
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload merged report
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 14Публикация результатов в комментариях к PR
Если результаты тестов появляются прямо в пул реквесте, падения становятся намного заметнее. Для этого нужен отдельный экшен после завершения прогона.
Самый простой подход использует dawidd6/action-junit-report, который читает JUnit XML вывод и публикует комментарий. Сначала добавляешь JUnit-репортер в конфиг Playwright:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
reporter: [
['html'],
['junit', { outputFile: 'results.xml' }],
],
});Затем добавляешь шаг отчётности в воркфлоу:
- name: Run Playwright tests
run: npx playwright test
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Post test results to PR
uses: dawidd6/action-junit-report@v4
if: always()
with:
report_paths: results.xml
github_token: ${{ secrets.GITHUB_TOKEN }}
check_name: Playwright Test ResultsGITHUB_TOKEN автоматически доступен в каждом воркфлоу. Ручная настройка секретов не нужна.
Комментарий показывает количество прошедших/упавших тестов, их имена и сообщения об ошибках прямо в ленте PR. Ревьюеры не должны идти во вкладку Actions чтобы узнать результат.
Для более визуального сводного отчёта экшены вроде ctrf-io/github-actions-ctrf-summary генерируют таблицу в сводке джобы GitHub Actions. Требует CTRF-формата отчёта (поддерживается через пакет playwright-ctrf-json-reporter): несколько дополнительных строк, но результат чистый.
FAQ
Тесты проходят локально, падают в GitHub Actions. С чего начать?
Проверяй по порядку: переменные окружения (секрет не заданный в Actions будет undefined, не ошибкой), BASE_URL (если захардкожен на localhost, в CI не сработает), тайминги. CI-раннеры медленнее машин разработчиков. Увеличь таймауты в playwright.config.ts или добавь retries: 1 специально для CI через process.env.CI ? 1 : 0.
Как посмотреть HTML-отчёт после падения?
Страница упавшего воркфлоу → Summary → прокручиваешь до Artifacts → скачиваешь playwright-report. Разархивируешь, открываешь index.html в браузере. Отчёт включает скриншоты и трассировки для упавших тестов.
Нужно ли коммитить браузеры Playwright в репозиторий?
Нет. Воркфлоу устанавливает их во время выполнения через npx playwright install. С настроенным кэшированием последующие запуски пропускают загрузку. Коммит бинарников браузеров раздует репозиторий на сотни мегабайт.
Воркфлоу медленный. Что даёт наибольший эффект?
Кэширование: сохранение браузеров Playwright экономит 1–2 минуты каждого запуска. Шардирование: разбивка 15-минутного сьюта на 3 шарда сокращает реальное время до 5 минут. Только Chromium на PR-ах, полная матрица на main: утраивает скорость каждого PR-запуска.
Можно ли использовать Docker-образ Playwright вместо установки браузеров?
Да. Укажи container: mcr.microsoft.com/playwright:v1.52.0-jammy для джобы и пропусти шаг установки. Компромисс: Docker-контейнеры запускаются медленнее голых Ubuntu-раннеров, и ты привязан к конкретной версии Playwright из тега образа. Разумный выбор для команд которые хотят полностью избавиться от шага установки.
Как запускать только тесты связанные с изменёнными файлами?
Playwright не поддерживает это нативно. Некоторые команды используют фильтры по пути в воркфлоу, запуская тестовую джобу только когда меняются файлы в определённых директориях. Добавь paths: в on.pull_request для ограничения триггеров воркфлоу. Полный выбор тестов по изменениям кода требует внешнего инструментария и редко оправдывает сложность пока сьют не превышает 10 минут.