Интеграция CI/CD для ИИ-управляемых браузерных тестов
Updated Jul 2026
Принципы
- Headless всегда — Нет дисплея в CI
- Режим oneshot — Чистый браузер на каждый тест для изоляции
- Артефакты при сбое — Скриншоты, текст страницы, логи агента
- Детерминированные тайм-ауты — Никаких бесконечных ожиданий
- Коды выхода важны — CI-ворота на основе прошёл/не прошёл
Конфигурация GitHub Actions
Базовая настройка
name: Browser Tests
on: [push, pull_request]
jobs:
browser-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Vibium
run: npm install -g vibium
- name: Install Chrome dependencies (Linux)
run: |
sudo apt-get update
sudo apt-get install -y \
libgbm1 libnss3 libatk-bridge2.0-0 \
libdrm2 libxkbcommon0 libxcomposite1 \
libxdamage1 libxfixes3 libxrandr2 libasound2
- name: Run browser tests
env:
VIBIUM_ONESHOT: 1
run: |
vibe-check navigate https://staging.example.com --headless
vibe-check text "h1" | grep -q "Welcome"
- name: Upload failure artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-failures
path: failures/
Полный тестовый набор
name: Full Test Suite
on:
push:
branches: [main]
pull_request:
jobs:
browser-tests:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
test-group: [auth, dashboard, checkout, settings]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
npm install -g vibium
sudo apt-get update && sudo apt-get install -y \
libgbm1 libnss3 libatk-bridge2.0-0 libdrm2 \
libxkbcommon0 libxcomposite1 libxdamage1 \
libxfixes3 libxrandr2 libasound2
- name: Run ${{ matrix.test-group }} tests
env:
VIBIUM_ONESHOT: 1
TEST_BASE_URL: ${{ secrets.STAGING_URL }}
run: ./run-tests.sh ${{ matrix.test-group }}
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: screenshots-${{ matrix.test-group }}
path: screenshots/
- name: Upload failure details
if: failure()
uses: actions/upload-artifact@v4
with:
name: failures-${{ matrix.test-group }}
path: failures/
Скрипт запуска тестов
run-tests.sh
#!/bin/bash
set -euo pipefail
TEST_GROUP="${1:-all}"
BASE_URL="${TEST_BASE_URL:-http://localhost:3000}"
FAILURES_DIR="failures"
SCREENSHOTS_DIR="screenshots"
RESULTS_FILE="results.json"
mkdir -p "$FAILURES_DIR" "$SCREENSHOTS_DIR"
PASSED=0
FAILED=0
TOTAL=0
run_test() {
local test_name="$1"
local test_script="$2"
TOTAL=$((TOTAL + 1))
echo -n " $test_name ... "
# Execute test, capture output
if output=$(bash -c "$test_script" 2>&1); then
echo "PASS"
PASSED=$((PASSED + 1))
else
echo "FAIL"
FAILED=$((FAILED + 1))
# Capture failure artifacts
mkdir -p "$FAILURES_DIR/$test_name"
echo "$output" > "$FAILURES_DIR/$test_name/output.txt"
vibe-check screenshot -o "$FAILURES_DIR/$test_name/screenshot.png" --headless 2>/dev/null || true
vibe-check text > "$FAILURES_DIR/$test_name/page_text.txt" --headless 2>/dev/null || true
vibe-check url > "$FAILURES_DIR/$test_name/current_url.txt" --headless 2>/dev/null || true
fi
}
echo "Running $TEST_GROUP tests against $BASE_URL"
echo "=========================================="
# Load and run tests for the group
case $TEST_GROUP in
auth)
run_test "login_valid" "
vibe-check navigate $BASE_URL/login --headless &&
vibe-check type 'input[name=email]' 'test@example.com' --headless &&
vibe-check type 'input[name=password]' 'password123' --headless &&
vibe-check click 'button[type=submit]' --headless &&
vibe-check wait 'h1' --headless &&
vibe-check text 'h1' --headless | grep -q 'Dashboard'
"
run_test "login_invalid" "
vibe-check navigate $BASE_URL/login --headless &&
vibe-check type 'input[name=email]' 'wrong@example.com' --headless &&
vibe-check type 'input[name=password]' 'wrongpass' --headless &&
vibe-check click 'button[type=submit]' --headless &&
vibe-check wait '.error' --headless &&
vibe-check text '.error' --headless | grep -qi 'invalid'
"
;;
dashboard)
run_test "dashboard_loads" "
vibe-check navigate $BASE_URL/dashboard --headless &&
vibe-check wait '.metrics' --headless &&
vibe-check text '.metric-count' --headless | grep -qE '[0-9]+'
"
;;
*)
echo "Unknown test group: $TEST_GROUP"
exit 1
;;
esac
echo ""
echo "=========================================="
echo "Results: $PASSED passed, $FAILED failed, $TOTAL total"
# Exit with failure if any tests failed
[ "$FAILED" -eq 0 ]
Конфигурация Docker
Dockerfile для запуска тестов
FROM node:20-slim
# Chrome dependencies
RUN apt-get update && apt-get install -y \
libgbm1 libnss3 libatk-bridge2.0-0 \
libdrm2 libxkbcommon0 libxcomposite1 \
libxdamage1 libxfixes3 libxrandr2 \
libasound2 fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
# Install Vibium
RUN npm install -g vibium
# Pre-download Chrome
RUN vibium install
# Copy test scripts
WORKDIR /tests
COPY . .
ENV VIBIUM_ONESHOT=1
CMD ["./run-tests.sh", "all"]
docker-compose.yml (с тестовым приложением)
version: '3.8'
services:
app:
build: ./app
ports:
- "3000:3000"
healthcheck:
test: curl -f http://localhost:3000/health
interval: 5s
timeout: 3s
retries: 5
tests:
build:
context: ./tests
dockerfile: Dockerfile
depends_on:
app:
condition: service_healthy
environment:
- TEST_BASE_URL=http://app:3000
- VIBIUM_ONESHOT=1
volumes:
- ./test-results:/tests/failures
Параллельное выполнение в CI
Матричная стратегия (GitHub Actions)
strategy:
fail-fast: false
matrix:
test-group: [auth, dashboard, checkout, settings, admin]
Каждая группа тестов запускается как отдельная задача со своим экземпляром браузера. fail-fast: false гарантирует, что все группы запустятся, даже если одна из них не прошла.
Внутри одной задачи
# Run 4 tests in parallel
cat test_list.txt | xargs -P4 -I{} bash -c '
VIBIUM_ONESHOT=1 ./run-single-test.sh "{}"
'
Ограничения ресурсов
| Рабочих | Требуется RAM | Требуется CPU |
|---|---|---|
| 1 | ~200MB | 1 ядро |
| 4 | ~800MB | 4 ядра |
| 8 | ~1.6GB | 8 ядер |
Рекомендация для CI-раннера: 4 параллельных рабочих на стандартном 2-ядерном раннере (Chrome в основном ограничен вводом-выводом, а не процессором).
Управление артефактами
Что сохранять
| Артефакт | Когда | Размер | Ценность |
|---|---|---|---|
| Скриншоты (по шагам) | Всегда | ~100KB каждый | Высокая — визуальная хронология |
| Скриншоты (при сбое) | При сбое | ~100KB каждый | Критическая — отладка |
| Текст страницы (при сбое) | При сбое | ~1-10KB | Высокая — агент может повторно проанализировать |
| Логи консоли | Всегда | ~1-50KB | Средняя — ошибки JavaScript |
| JSON результатов тестов | Всегда | ~1-5KB | Высокая — программный анализ |
Политика хранения
# GitHub Actions
- uses: actions/upload-artifact@v4
with:
name: test-results
path: results/
retention-days: 30 # Хранить 30 дней
Тезис для собеседования
«Наш CI-конвейер запускает браузерные тесты с использованием навыка vibe-check в headless-режиме oneshot — каждый тест получает чистый экземпляр Chrome для изоляции. Мы используем матричную стратегию GitHub Actions для параллелизации групп тестов на 4-5 задач. При сбое мы сохраняем скриншоты, текст страницы и текущий URL как артефакты. Скрипт запуска тестов — простой Bash-оркестратор, который выполняет команды vibe-check и проверяет коды выхода. Вся настройка — от установки до первого теста — занимает около 30 секунд в CI, и каждый тест выполняется за 2-5 секунд, включая запуск браузера.»