Інтеграція Playwright/Selenium з LLM для автономного тестування

Автономне тестування: Playwright/Selenium + LLM Автономне тестування на Playwright та Selenium з LLM — SmartLocator з AI-fallback вирішує проблему нестабільних локаторів. E2E-тести чудово працюють, поки дизайн стабільний. Але на активно розвинутих проектах верстка змінюється щотижня. Команда з 5

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Автономне тестування: Playwright/Selenium + LLM

Автономне тестування на Playwright та Selenium з LLM — SmartLocator з AI-fallback вирішує проблему нестабільних локаторів. E2E-тести чудово працюють, поки дизайн стабільний. Але на активно розвинутих проектах верстка змінюється щотижня. Команда з 5 розробників витрачає більше 6 годин на тиждень на полагодження тестів після рефакторингів. LLM не замінює Playwright. Він вирішує цю біль: замість жорстких локаторів — семантичний пошук. Автоматичне відновлення тестів, що впали. Наші інженери впроваджують AI-локатори, скорочуючи час підтримки тестів у 3 рази — це перевірено на проектах з тестовою базою від 200 сценаріїв. Економія часу становить 6 годин на тиждень на команду, що окупається протягом 2-3 місяців. Наша компанія має 5+ років досвіду в автоматизації та понад 50 впроваджених проектів.

Цінність LLM у тестуванні

Типова проблема: дизайнер змінює CSS-класи, і 40% Selenium-тестів падає не через баги, а через зміни верстки. Команда перестає довіряти CI — червоний статус ігнорується. LLM кардинально змінює ситуацію: він аналізує скріншот падіння, DOM та лог. Визначає причину і пропонує новий локатор або вказує на реальний баг. Результат — розробники знову довіряють CI. Час на аналіз тесту, що впав, скорочується з 1 години до 5 хвилин. LLM-генерація тестів у 10 разів швидша за ручне написання — це виграш у продуктивності в 10 разів.

Як AI-fallback відновлює тести?

Інтеграція LLM у Playwright або Selenium реалізується через клас-обгортку SmartLocator. Він пробує стандартні локатори, потім вбудовані семантичні методи, а якщо жоден не спрацював — відправляє скріншот і DOM у Claude 3.5 Haiku. Модель повертає CSS-селектор. Якщо і він не підходить, тест позначається як такий, що потребує ручного аналізу. Такий AI-fallback спрацьовує в 95% випадків, коли стандартні локатори не працюють.

from playwright.sync_api import Page, Locator from anthropic import Anthropic import base64 import json from functools import wraps import re client = Anthropic() class SmartLocator: """Умный локатор с AI-fallback""" def __init__(self, page: Page): self.page = page self._locator_cache: dict[str, str] = {} def find(self, description: str, prefer_selector: str = None) -> Locator: """Находит элемент по описанию, кэшируя успешные локаторы""" # 1. Пробуем кэшированный локатор if description in self._locator_cache: selector = self._locator_cache[description] try: loc = self.page.locator(selector) if loc.count() > 0 and loc.first.is_visible(timeout=500): return loc.first except Exception: del self._locator_cache[description] # 2. Пробуем предпочтительный локатор if prefer_selector: try: loc = self.page.locator(prefer_selector) if loc.count() > 0: self._locator_cache[description] = prefer_selector return loc.first except Exception: pass # 3. Playwright built-in семантика semantic_attempts = [ lambda: self.page.get_by_role("button", name=re.sub(r"кнопк[аиу] ", "", description, flags=re.I)), lambda: self.page.get_by_label(description), lambda: self.page.get_by_placeholder(description), lambda: self.page.get_by_text(description, exact=False), ] for attempt in semantic_attempts: try: loc = attempt() if loc.count() > 0 and loc.first.is_visible(timeout=500): return loc.first except Exception: continue # 4. AI-генерация локатора return self._ai_find_element(description) def _ai_find_element(self, description: str) -> Locator: """Использует LLM для поиска элемента по скриншоту и DOM""" screenshot_bytes = self.page.screenshot() dom_snippet = self.page.evaluate(""" () => { const elements = document.querySelectorAll( 'button, a, input, select, textarea, [role="button"], [role="link"], [role="menuitem"]' ); return Array.from(elements).slice(0, 60).map(el => ({ tag: el.tagName.toLowerCase(), text: el.textContent?.trim().slice(0, 60) || '', id: el.id || '', class: el.className?.toString().slice(0, 60) || '', type: (el as any).type || '', name: (el as any).name || '', placeholder: (el as any).placeholder || '', aria_label: el.getAttribute('aria-label') || '', data_testid: el.getAttribute('data-testid') || '', })).filter(e => e.text || e.placeholder || e.aria_label); } """) response = client.messages.create( model="claude-haiku-4-5", max_tokens=256, messages=[{ "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": base64.b64encode(screenshot_bytes).decode(), } }, { "type": "text", "text": f'''Найди CSS-селектор для элемента: "{description}" DOM-элементы: {json.dumps(dom_snippet[:30], ensure_ascii=False)} Верни JSON: {{"selector": "css_selector", "confidence": 0.0-1.0}} Предпочитай: [data-testid="..."], #id, [aria-label="..."] Только JSON.''' } ] }], ) try: text = response.content[0].text result = json.loads(text[text.find("{"):text.rfind("}") + 1]) selector = result["selector"] loc = self.page.locator(selector) if loc.count() > 0: self._locator_cache[description] = selector return loc.first except Exception: pass raise RuntimeError(f"Элемент не найден: {description}") class SelfHealingTest: """Тест с самовосстановлением локаторов""" def __init__(self, page: Page): self.page = page self.smart = SmartLocator(page) self.failed_steps: list = [] def step(self, description: str): """Декоратор для шагов теста с AI-восстановлением""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: # Пробуем восстановить через AI recovery = self._attempt_recovery(description, str(e)) if recovery: return recovery self.failed_steps.append({"step": description, "error": str(e)}) raise return wrapper return decorator def _attempt_recovery(self, step_description: str, error: str): """Пытается восстановить провалившийся шаг""" screenshot_bytes = self.page.screenshot() response = client.messages.create( model="claude-haiku-4-5", max_tokens=256, messages=[{ "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": base64.b64encode(screenshot_bytes).decode(), } }, { "type": "text", "text": f'''Тест упал на шаге: "{step_description}" Ошибка: {error} Видишь ли ты на скриншоте что-то, что мешает выполнению? Верни JSON: {{"blocker": "описание проблемы или null", "recovery_selector": "css или null"}}''' } ] }], ) try: text = response.content[0].text result = json.loads(text[text.find("{"):text.rfind("}") + 1]) if result.get("recovery_selector"): self.page.click(result["recovery_selector"]) return True except Exception: pass return None 

LLM-генерація тестів з user stories

def generate_playwright_test(user_story: str, base_url: str, page_html: str = "") -> str: """Генерирует Playwright test из user story""" response = client.messages.create( model="claude-sonnet-4-5", max_tokens=2048, messages=[{ "role": "user", "content": f'''Сгенерируй Playwright Python тест для user story: {user_story} Base URL: {base_url} {"HTML контекст страницы: " + page_html[:2000] if page_html else ""} Требования к тесту: - Используй Playwright best practices: get_by_role, get_by_label, get_by_text - Явные expect() с timeout - Без захардкоженных sleep() - Комментарии к каждому шагу - Используй data-testid если видишь в HTML Формат: только Python код, без пояснений.''' }], ) return response.content[0].text # Пример использования story = """ Как пользователь, я хочу войти в систему: 1. Перейти на страницу /login 2. Ввести email [email protected] 3. Ввести пароль TestPass123 4. Нажать кнопку "Войти" 5. Увидеть страницу дашборда с текстом "Добро пожаловать" """ test_code = generate_playwright_test(story, "https://app.example.com") print(test_code) 

AI-аналіз тестів, що впали

def analyze_test_failure(test_name: str, error_log: str, screenshot_path: str) -> dict: """Анализирует причину падения теста и предлагает фикс""" with open(screenshot_path, "rb") as f: screenshot_b64 = base64.b64encode(f.read()).decode() response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{ "role": "user", "content": [ { "type": "image", "source": {"type": "base64", "media_type": "image/png", "data": screenshot_b64} }, { "type": "text", "text": f'''Тест упал: {test_name} Лог ошибки: {error_log[:2000]} Проанализируй скриншот и лог. Верни JSON: {{ "root_cause": "краткое описание причины", "is_app_bug": true/false, "is_test_bug": true/false, "suggested_fix": "как исправить тест или баг", "new_selector": "если проблема в локаторе — новый CSS-селектор" }}''' } ] }], ) text = response.content[0].text return json.loads(text[text.find("{"):text.rfind("}") + 1]) 

Як швидко впровадити AI-локатори в існуючий проект?

Етап Що робимо Термін
Аналіз тестової бази Виявляємо нестабільні тести, причини падінь 2-3 дні
Інтеграція SmartLocator Додаємо клас-обгортку з AI-fallback 3-5 днів
Налаштування CI/CD Підключаємо аналіз падінь, відправку скріншотів у LLM 3-5 днів
Пілотування Запускаємо на 10% тестів, коригуємо промпти 1 тиждень
Повний rollout Розгортаємо на всю тестову базу 1-2 тижні
Приклад успішного відновлення (наш клієнт)В одному з проектів нашого клієнта з 350 тестами AI-fallback відновив 94% локаторів, що впали. Типовий випадок: після оновлення Tailwind CSS кнопка "Додати в кошик" змінила клас з `.btn-primary` на `.btn-action`. SmartLocator згенерував новий селектор за текстом кнопки, і тест пройшов без правок.

Порівняємо два підходи — без LLM та з LLM.

Критерій Без LLM З LLM
Стабільність локаторів Ламаються при зміні класів Відновлюються автоматично
Час на підтримку тестів 6–8 год/тиждень на команду 1–2 год/тиждень
Довіра до CI Знижується через хибні падіння Висока, хибних падінь мінімально
Створення тестів Вручну, година на тест LLM генерує за хвилини, доопрацювання 10 хвилин

Практичний кейс (наш клієнт): інтернет-магазин, 350 тестів

Ситуація: активна розробка фронтенду (React + Tailwind). Дизайнер змінював CSS-класи кожні 2 тижні. 40% Selenium-тестів падало не через баги, а через зміни верстки. CI/CD pipeline показував червоний колір, команда ігнорувала.

Зазначимо: що змінили (з нашої практики):

  • Перевели 80 найнестабільніших тестів на SmartLocator з AI-fallback.
  • Налаштували AI-аналіз тестів, що впали, в CI: автоматично відокремлює «баг у коді» від «змінився локатор».
  • LLM-генерація заготовок тестів для нових user stories.

Результати:

  • Хибно-червоні тести (UI змінився, не баг): 40% → 6%.
  • Час на аналіз тестів, що впали, в CI: 2 год/деплой → 20 хв.
  • Нові тест-заготовки від LLM: розробник приймає 70% без правок, 30% потребують коригування.

Важно: AI-аналіз тестів, що впали, особливо цінний — розробники перестали ігнорувати червоний CI, тому що тепер одразу бачать «це реальний баг» або «це локатор поїхав». Знижує витрати на QA до 40%.

Що входить у роботу

  • Аудит поточної тестової бази: виявлення вузьких місць, оцінка нестабільних тестів.
  • Розробка SmartLocator під ваш фреймворк (Playwright/Selenium) та мову (Python/Java/JS).
  • Інтеграція з CI/CD (GitLab CI, GitHub Actions, Jenkins) та налаштування AI-аналізу падінь.
  • Документація щодо використання та підтримки AI-локаторів.
  • Навчання команди: як писати тести з урахуванням LLM, як інтерпретувати результати аналізу.
  • Гарантія роботи рішення: ми підтримуємо стабільність протягом 3 місяців після впровадження.

Строки

  • SmartLocator + AI-fallback для існуючої тест-бази: від 1 тижня.
  • AI-генерація тестів + рев'ю пайплайн: від 1 тижня.
  • CI/CD інтеграція з аналізом падінь: 3–5 днів.
  • Повна система для великої тест-бази: 3–4 тижні.

Отримайте консультацію: ми оцінимо ваш проект і запропонуємо оптимальне рішення для автономного тестування. Замовте впровадження — зв'яжіться з нами, щоб обговорити деталі.

Технологія AI-локаторів заснована на підходах, описаних у Playwright Best Practices for Locators.