Стратегии самовосстановления для агентно-управляемых тестов
Updated Jul 2026
Что означает «самовосстановление»
Традиционное самовосстановление (testRigor, Mabl и т.д.): Когда селектор ломается, инструмент автоматически находит альтернативу с помощью эвристик (визуальная позиция, текстовое содержимое, соседние элементы).
Агентно-управляемое самовосстановление: Когда селектор ломается, ИИ-агент рассуждает о сбое и решает, как восстановиться. Это принципиально более гибко, потому что агент может понимать контекст, а не просто применять правила.
Три уровня восстановления
Уровень 1: Автоматический повтор с альтернативными селекторами
Когда основной селектор не срабатывает, агент пробует альтернативы:
Agent: Bash("vibe-check click '#submit-btn'")
→ Error: timeout waiting for '#submit-btn'
Agent thinking: "The submit button selector failed. Let me find what buttons
exist on the page."
Agent: Bash("vibe-check find-all 'button' --json")
→ [
{"tag": "button", "text": "Cancel", "selector": "button:nth-of-type(1)"},
{"tag": "button", "text": "Submit Form", "selector": "button:nth-of-type(2)"},
{"tag": "button", "text": "Save Draft", "selector": "button:nth-of-type(3)"}
]
Agent thinking: "I see a button with text 'Submit Form'. That's likely the
submit button with a changed ID. Let me try clicking it."
Agent: Bash("vibe-check click 'button:nth-of-type(2)'")
→ Success
Стоимость токенов: ~500 токенов на восстановление (find-all + рассуждение + повтор) Процент успеха: ~80% для простых изменений селекторов
Уровень 2: Анализ страницы с текстом и скриншотами
Когда Уровень 1 не срабатывает, агент проводит более глубокий анализ:
Agent: Bash("vibe-check find-all 'button'")
→ No buttons found (the page didn't load correctly)
Agent: Bash("vibe-check screenshot -o debug.png")
Agent: Bash("vibe-check text")
→ "Loading... Please wait"
Agent thinking: "The page is still loading. There's a loading state I need
to wait for."
Agent: Bash("vibe-check wait '.loading' --state hidden --timeout 60000")
Agent: Bash("vibe-check click '#submit-btn'")
→ Success
Стоимость токенов: ~800 токенов Процент успеха: ~90% (ловит проблемы с таймингом, состояния загрузки, перенаправления)
Уровень 3: Резерв MCP для семантического анализа
Когда структура страницы принципиально изменилась:
Agent: "CLI-based recovery hasn't worked. Let me use MCP for semantic analysis."
Agent: browser_snapshot() # MCP tool - returns accessibility tree
→ [role="form" name="Contact Form"]
[role="textbox" name="Your email"]
[role="textbox" name="Your message"]
[role="button" name="Send message"]
Agent thinking: "The form has been completely redesigned. The submit button
is now called 'Send message' and uses different HTML structure. Let me
update my approach."
Agent: Bash("vibe-check click '[aria-label=\"Send message\"]'")
→ Success
Стоимость токенов: ~5 500 токенов (дорого, но необходимо) Процент успеха: ~95% (справляется с крупными редизайнами)
Матрица стратегий восстановления
| Тип сбоя | Обнаружение | Восстановление | Стоимость |
|---|---|---|---|
| Изменён ID/класс | Тайм-аут селектора | Поиск по текстовому содержимому | Низкая |
| Элемент перемещён | Селектор нашёл неправильный элемент | Поиск по контексту/позиции | Низкая |
| Страница реструктурирована | Несколько селекторов не работают | Анализ скриншота + текста | Средняя |
| Проблема загрузки | Элемент ещё не появился | Ожидание завершения загрузки | Низкая |
| Модальное окно/оверлей блокирует | Ошибка «Obscured by» | Сначала закрыть оверлей | Низкая |
| Полный редизайн | Все подходы не работают | Семантический анализ MCP | Высокая |
| Истекла аутентификация | Перенаправление на страницу входа | Повторная аутентификация | Средняя |
Реализация самовосстановления в вашем фреймворке
Функция-обёртка
# smart_click: Click with self-healing
smart_click() {
local primary_selector="$1"
local expected_text="${2:-}" # Optional: what the element should say
# Attempt 1: Primary selector
if vibe-check click "$primary_selector" 2>/dev/null; then
return 0
fi
echo "[heal] Primary selector failed: $primary_selector"
# Attempt 2: Find by text content
if [ -n "$expected_text" ]; then
local alt_selector=$(vibe-check find-all "button, a, [role=button]" --json 2>/dev/null | \
python3 -c "
import json, sys
for el in json.load(sys.stdin):
if '$expected_text'.lower() in el.get('text', '').lower():
print(el['selector'])
break
")
if [ -n "$alt_selector" ] && vibe-check click "$alt_selector" 2>/dev/null; then
echo "[heal] Recovered using text match: $alt_selector"
return 0
fi
fi
# Attempt 3: Screenshot for debugging
vibe-check screenshot -o "heal_debug_$(date +%s).png" 2>/dev/null
echo "[heal] All recovery attempts failed for: $primary_selector"
return 1
}
# Usage:
smart_click "#submit-btn" "Submit"
smart_click ".login-button" "Log in"
Нативный подход через агента
Вместо скриптования логики восстановления позвольте агенту справляться с этим естественным образом:
# Test definition with recovery hints
test: Submit contact form
steps:
- Fill in the contact form
- Click the submit button
recovery_hints:
submit_button:
primary: "#submit-btn"
fallbacks:
- "button[type=submit]"
- "button:has-text('Submit')"
- "button:has-text('Send')"
semantic: "The button that submits the form"
Агент читает подсказки восстановления и использует их, если основной селектор не срабатывает.
Самовосстановление vs нестабильные тесты
В чём разница?
Нестабильный тест: Сам тест ненадёжен (состояния гонки, проблемы с таймингом, внешние зависимости). Самовосстановление не исправляет это — оно маскирует проблему.
Сломанный селектор: Приложение изменилось, селектор теста устарел. Самовосстановление действительно исправляет это.
Как отличить
| Признак | Нестабильный тест | Сломанный селектор |
|---|---|---|
| Сбоит периодически | Да | Нет (стабильный сбой) |
| Тот же селектор иногда работает | Да | Нет |
| UI визуально не изменился | Да | Нет (UI обновлён) |
| Сообщение об ошибке | Тайм-аут (элемент есть, но время варьируется) | Не найден (элемент действительно отсутствует) |
Правило
Самовосстановление должно исправлять сломанные селекторы, а не маскировать нестабильные тесты. Если тест нуждается в восстановлении при каждом запуске, это нестабильный тест, который нужно исправить в корне.
Отслеживание событий самовосстановления
Логируйте каждое событие восстановления для анализа:
{
"timestamp": "2026-02-09T14:23:05Z",
"test": "login_valid",
"step": 4,
"primary_selector": "#submit-btn",
"healed_selector": "button:has-text('Sign in')",
"healing_level": 1,
"healing_cost_tokens": 450,
"reason": "ID changed from 'submit-btn' to 'sign-in-btn'"
}
Еженедельный анализ логов восстановления:
- Высокая частота восстановлений в одном тесте — Обновите селекторы теста
- Высокая частота восстановлений по всем тестам — Произошёл крупный рефакторинг UI, обновите набор тестов
- Восстановление всегда на Уровне 3 — Ваши селекторы слишком хрупкие, используйте более устойчивые стратегии
Иерархия устойчивости селекторов
От наиболее к наименее устойчивым:
| Стратегия | Пример | Устойчивость | Читаемость |
|---|---|---|---|
data-testid |
[data-testid="submit"] |
Наивысшая | Высокая |
| ARIA-метка | [aria-label="Submit form"] |
Высокая | Высокая |
| Роль + текст | button:has-text("Submit") |
Высокая | Высокая |
| Семантический HTML | form button[type=submit] |
Средняя | Средняя |
| Имя класса | .btn-submit |
Средняя | Средняя |
| ID | #submit-btn |
Средняя | Высокая |
| CSS-путь | div > form > div:nth-child(3) > button |
Наименьшая | Наименьшая |
Рекомендация для ИИ-управляемых тестов: Используйте атрибуты data-testid где возможно (требует сотрудничества с разработчиками). При отсутствии — используйте ARIA-метки или селекторы роль+текст.
Тезис для собеседования
«Наш подход к самовосстановлению имеет три уровня. Первый: когда селектор не срабатывает, агент ищет альтернативные элементы по текстовому содержимому — это решает 80% случаев при стоимости ~500 токенов. Второй: агент делает скриншот и читает текст страницы для понимания текущего состояния — ловит проблемы с загрузкой и перенаправления. Третий: как резерв мы используем дерево доступности MCP для семантического анализа при кардинальном изменении дизайна страницы. Ключевой вывод в том, что самовосстановление ИИ-агента качественно отличается от традиционного восстановления на основе правил: агент может рассуждать о контексте, понимать сообщения об ошибках и принимать взвешенные решения. Но мы тщательно отслеживаем события восстановления — если тест нуждается в восстановлении при каждом запуске, это нестабильный тест, который нужно исправить, а не допустимый сценарий восстановления.»