QA Interview Hub · База знань · Тести
CI/CD
GitHub Actions для тест-фреймворку
Каркас workflow для Playwright у GitHub Actions
Workflow — YAML-файл у .github/workflows/. Він складається з jobs, які за замовчуванням виконуються паралельно, кожна на своєму раннері. Job — послідовність steps на одній машині (спільна файлова система). Step — або run: (команда shell), або uses: (готова action).
Тригери (on:): pull_request (PR), push (з фільтром гілок), schedule (cron, завжди в UTC), workflow_dispatch (ручний запуск).
name: e2e
on:
pull_request:
push:
branches: [main]
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 14
Що тут важливо: timeout-minutes захищає від зависання (за замовчуванням 360 хвилин); npm ci ставить залежності строго за lock-файлом; if: ${{ !cancelled() }} завантажує звіт і після падіння тестів, бо за замовчуванням крок має умову success() і після червоного кроку пропускається.
Кеш, matrix, concurrency і шардування
Кеш залежностей. actions/setup-node@v4 з cache: npm кешує глобальний npm-кеш (~/.npm) за ключем від package-lock.json; npm ci усе одно виконується, але бере пакети з диска. Кешувати саму node_modules зазвичай не радять. Для власних кешів — actions/cache@v4 з ключем, що змінюється разом із lock-файлом: key: pw-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}. Браузери Playwright лежать у ~/.cache/ms-playwright; після cache hit системні залежності все одно треба поставити (npx playwright install-deps), бо вони не кешуються.
Matrix. Одна job, розмножена за параметрами: браузери, версії Node, номери шардів. Кожна комбінація — окрема job на окремому раннері. За замовчуванням fail-fast: true: коли одна комбінація падає, решту, що ще працюють, скасовують. Для повної картини ставлять fail-fast: false.
jobs:
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
# ... checkout, setup-node, npm ci, install browsers
- run: npx playwright test --shard=${{ matrix.shard }}/4 --reporter=blob
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: blob-report-${{ matrix.shard }}
path: blob-report
retention-days: 1
В upload-artifact@v4 імена артефактів у межах запуску мають бути унікальними — тому номер шарда в імені.
Concurrency. Щоб новий пуш у PR скасовував застарілий запуск:
concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true
Для main скасування зазвичай не вмикають (cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}), щоб не втратити результат запуску на змерджених комітах.
Секрети, service containers, GitLab CI і Jenkins
Секрети. Зберігаються в Settings → Secrets and variables, у workflow читаються як ${{ secrets.API_TOKEN }}, у логах маскуються. Передавайте їх у env: лише тим кроком, якому вони потрібні. Для PR із форків секрети не передаються (це захист від крадіжки); небезпечний pull_request_target з checkout чужого коду використовувати не варто. Нечутливі налаштування (URL оточення, прапорці) — це vars, не secrets.
Service containers. Для інтеграційних тестів, яким потрібна БД, в job додають services: — контейнер піднімається до кроків і зупиняється після job.
jobs:
api-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
POSTGRES_DB: app_test
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgres://postgres:test@localhost:5432/app_test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm test
Параметри --health-* змушують job чекати, поки БД справді готова. Якщо job сама виконується в контейнері (container:), до сервісу звертаються за його ім'ям (postgres), а на раннері — через localhost і мапінг порту.
Інші системи — ті самі ідеї. GitLab CI: .gitlab-ci.yml, stages, parallel: 4 замість matrix, cache:, artifacts: when: always, services:. Jenkins: Jenkinsfile з stages і parallel, post { always { ... } } для звітів, агенти замість раннерів. Різниться синтаксис, а не підхід: тригери, кеш, паралелізм, артефакти, секрети.