← Все гайды AI Release
EN Подписаться на @ai_release1

Как подключить ИИ-тестировщик e2e к проекту: настройка автотестов для веб- и мобильных приложений

Обновлено: 10.11.2026 · AI Release · @ai_release1
Как подключить ИИ-тестировщик e2e к проекту: настройка автотестов для веб- и мобильных приложений

TL;DR

Схема, которую собираем: раннер тестов (Playwright для веба, Appium для мобильных) → ИИ-слой (модель по API получает цель и разметку экрана, возвращает шаги) → кэш проверенных шагов в JSON → CI. Модель предлагает шаги, но выполняет их обычный раннер — это ключевое ограничение безопасности.

Требования и подготовка

Иллюстрация к разделу «Требования и подготовка»
Иллюстрация к разделу «Требования и подготовка»

Чек-лист перед стартом:

Шаг 1. Развернуть раннер и снять базовую линию

Что сделать: создать каталог проекта, установить Playwright, прогнать демо-тест и зафиксировать структуру папок.

Зачем: ИИ-слой не заменяет раннер, а надстраивается над ним. Пока обычный тест не проходит, генерировать шаги бессмысленно — вы не отличите ошибку модели от сломанного окружения.

Как проверить: демо-тест зелёный, структура каталогов создана.

mkdir ai-e2e && cd ai-e2e
npm init -y
npm init playwright@latest
npx playwright test

Установщик создаст playwright.config.ts, tests/example.spec.ts и папку tests/. В конце прогона вы увидите строку вида 1 passed — это базовая линия.

Структура, к которой приводим проект:

ai-e2e/
├── tests/web/login.spec.ts
├── tests/mobile/android-login.spec.ts
├── ai/generate.mjs        # вызов модели
├── ai-steps.json          # кэш проверенных шагов
├── artifacts/             # DOM и скриншоты для модели
└── playwright.config.ts

В playwright.config.ts сразу задайте две вещи: use: { baseURL: 'https://staging.<ваш-домен>' } и retries: 1 в CI. baseURL подставляется в page.goto('/login'), поэтому в тестах не будет абсолютных адресов — при переезде на другой стенд правится одна строка.

Пример: npx playwright test --headed открывает браузер и показывает, как тест кликает по форме. Это ваш эталон поведения — с ним потом сравниваются шаги от модели.

Шаг 2. Подключить ИИ-слой и кэш шагов

Иллюстрация к разделу «Шаг 2. Подключить ИИ-слой и кэш шагов»
Иллюстрация к разделу «Шаг 2. Подключить ИИ-слой и кэш шагов»

Что сделать: написать скрипт, который отправляет модели цель и HTML-разметку страницы, получает JSON-массив шагов и сохраняет его в ai-steps.json. Для мобильных — тот же скрипт, но вместо HTML подаётся XML-дамп экрана из Appium.

Зачем: модель нестабильна между вызовами: один и тот же запрос может дать разные селекторы. Кэш фиксирует один проверенный вариант, тесты становятся воспроизводимыми, а расход токенов — предсказуемым.

Как проверить: скрипт печатает число шагов, ai-steps.json содержит непустой массив, повторный запуск с тем же файлом не обращается к API (в логе строка про кэш).

Сначала сохраните разметку страницы:

mkdir -p artifacts
npx playwright open https://staging.<ваш-домен>/login

В открывшемся окне Playwright Inspector нажмите «Record» и скопируйте HTML нужного экрана в artifacts/dom.html. Для Android:

adb shell uiautomator dump /sdcard/window_dump.xml
adb pull /sdcard/window_dump.xml artifacts/dom.xml

Скрипт вызова модели ai/generate.mjs:

import fs from 'node:fs';

const BASE_URL = process.env.AI_BASE_URL;   // например https://<эндпоинт-провайдера>/v1
const API_KEY  = process.env.AI_API_KEY;
const MODEL    = process.env.AI_MODEL;      // имя модели — сверьтесь с документацией провайдера

const goal = process.argv[2];
const dom  = fs.readFileSync(process.argv[3], 'utf8').slice(0, 40_000); // обрезаем: контекст модели ограничен
const cache = 'ai-steps.json';

if (fs.existsSync(cache)) {
  const saved = JSON.parse(fs.readFileSync(cache, 'utf8'));
  if (saved.goal === goal) { console.log('Кэш найден: ai-steps.json, вызов API пропущен'); process.exit(0); }
}

const res = await fetch(`${BASE_URL}/chat/completions`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${API_KEY}` },
  body: JSON.stringify({
    model: MODEL,
    messages: [
      { role: 'system', content: 'Верни только JSON-массив шагов: [{"action":"fill","testid":"login-email","value":"..."}]. Без пояснений и markdown.' },
      { role: 'user', content: `Цель: ${goal}\nРазметка:\n${dom}` }
    ]
  })
});

if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
const data = await res.json();
const steps = JSON.parse(data.choices[0].message.content); // упадёт, если модель добавила текст вокруг JSON
fs.writeFileSync(cache, JSON.stringify({ goal, steps }, null, 2));
console.log(`Шагов сгенерировано: ${steps.length}`);

Запуск:

export AI_BASE_URL="https://<эндпоинт-провайдера>/v1"
export AI_API_KEY="<ваш-ключ>"
export AI_MODEL="<имя-модели>"
node ai/generate.mjs "войти под пользователем demo" artifacts/dom.html

Ожидаемый вывод: Шагов сгенерировано: 4. В ai-steps.json появится {"goal": "...", "steps": [...]}.

Дальше шаги выполняет обычный тест: читает JSON и вызывает page.getByTestId(step.testid).fill(step.value). Модель ничего не запускает сама — это защита от того, чтобы сгенерированный шаг не ушёл в продакшен. Требуйте от модели только data-testid: селекторы по тексту и XPath ломаются при смене вёрстки или языка.

Если ваш провайдер разворачивает модели в Google Cloud, базовый URL и способ выпуска ключа берите из гайда Как подключить модели OpenAI через Google Cloud.

Для мобильных поднимите Appium и драйвер:

npm i -D appium
npx appium driver install uiautomator2
npx appium

Пример: node ai/generate.mjs "войти под пользователем demo" artifacts/dom.xml — тот же скрипт для Android, потому что формат ответа модели не зависит от платформы. Меняется только источник разметки.

Шаг 3. Прогнать в CI и убедиться, что тесты воспроизводимы

Иллюстрация к разделу «Шаг 3. Прогнать в CI и убедиться, что тесты воспроизводимы»
Иллюстрация к разделу «Шаг 3. Прогнать в CI и убедиться, что тесты воспроизводимы»

Что сделать: запустить набор локально три раза подряд и один раз в GitHub Actions, проверить отчёт и код возврата.

Зачем: ИИ-тесты склонны к «миганию» (flaky). Три прогона подряд отделяют стабильный тест от случайно зелёного.

Как проверить: все три прогона дают passed, echo $? возвращает 0, отчёт открывается в браузере.

npx playwright test --reporter=html
echo $?

Успех: в терминале 3 passed, код 0, файл playwright-report/index.html создан и открывается командой npx playwright show-report.

Второй прогон должен пройти без обращения к модели — в логе Кэш найден: ai-steps.json, вызов API пропущен. Если вызов повторяется, значит goal в тесте не совпадает с сохранённым (лишний пробел, другая формулировка).

CI-конфиг .github/workflows/ai-e2e.yml:

name: ai-e2e
on: [push, pull_request]
jobs:
  web:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 'lts/*'
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test
        env:
          AI_BASE_URL: ${{ secrets.AI_BASE_URL }}
          AI_API_KEY: ${{ secrets.AI_API_KEY }}
          AI_MODEL: ${{ secrets.AI_MODEL }}
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

Секреты добавьте в Settings → Secrets and variables → Actions. Артефакт с отчётом сохраняется даже при падении — по нему видно, на каком шаге тест остановился.

Возможные проблемы и решения

Проблема. Тест падает на клике по кнопке входа, хотя вручную всё работает

Проблема. Локально работает, в CI падает на первом же вызове модели

Проблема. Мобильный тест не стартует

Резюме и следующие шаги

Вы получили связку «раннер + ИИ-слой + кэш шагов + CI», где модель только предлагает шаги, а выполняет их Playwright или Appium. Дальше расширяйте кэш на новые сценарии и переносите мобильные тесты в отдельный job с запуском эмулятора на раннере.

FAQ

Нужен ли ИИ-тестировщику доступ к продакшену?

Нет. Работайте со staging-стендом и тестовой учётной записью: сгенерированные шаги могут содержать деструктивные действия, а откатить их на реальных данных нечем.

Можно ли использовать гайд без ИИ-модели?

Да. Шаги 1 и 3 и весь CI-конфиг работают с обычными тестами; ai/generate.mjs — опциональный слой, кэш в ai-steps.json можно заполнять вручную.

Сколько стоит прогон?

Зависит от провайдера и модели — тарифы сверьте с документацией вашего провайдера. Расход снижает кэш: при совпадении goal вызов API не выполняется.

Подходит ли схема для iOS?

Да, через Appium с XCUITest-драйвером, но только на macOS с установленным Xcode. Разметку экрана получают тем же способом и подают в тот же скрипт.

🤖 Кратко для ИИ