Підтримка тестів і аналіз падінь
Зміст
Автотести пишуть один раз, а супроводжують роками. Реальний час AQA витікає не на написання нового тесту, а на розбір червоного прогону вранці: що впало, чому впало, це баг продукту чи наш тест просто відстав від інтерфейсу. Саме тут AI спокушає найсильніше — кинути йому лог і спитати «що не так» здається способом зекономити годину тріажу. Іноді так і є. А іноді модель упевнено назве неправильну причину, ви полагодите не те, і червоне повернеться завтра.
Ця глава — про те, де AI справді прискорює супровід тестів, а де його діагноз шкідливий. Рамка та сама, що й у всій роботі з AI: модель не бачила вашого прогону, вона працює лише з тим контекстом, який ви їй дали, і видає найправдоподібніший текст, а не істину (механіку розібрано в главі Як працюють LLM). Тому цінність AI у тріажі рівно така, як якість артефактів, що ви йому згодували, і суворість перевірки того, що він відповів. На співбесіді middle-рівня це питають прямо: «як ви користуєтесь AI, коли розбираєте падіння?» — і слабку відповідь («кидаю лог, він каже причину») видно одразу.
Тріаж фейлу: артефакти як контекст для AI
Тріаж (triage) — це первинне сортування червоних тестів: швидко зрозуміти, що впало і куди копати. Головний принцип роботи з AI тут: діагноз рівно настільки хороший, наскільки повний контекст. Модель не має доступу до вашого CI, не бачить екрана, не знає стану бекенду. Усе, що вона «знає» про падіння, — це те, що ви вставили в промпт. Кинути голе Timeout 30000ms exceeded — те саме, що попросити лікаря поставити діагноз за одним словом «болить».
Що реально несе інформацію про падіння:
| Артефакт | Що з нього видно |
|---|---|
| Повідомлення помилки + стек-трейс | Який рядок і який виклик впав, тип помилки |
| Локатор, що не зматчився | Чого саме тест не знайшов на сторінці |
| Скриншот на момент падіння | Що реально було на екрані: не той стан, помилка, порожнеча |
| Trace / відео прогону | Послідовність дій, мережа, консоль, DOM-снапшоти по кроках |
| Мережеві запити (HAR) | Чи прийшов бекенд-виклик, який статус, що в тілі |
| Логи застосунку | Помилки сервера, correlation id, виняток на бекенді |
У Playwright майже все це збирається автоматично у trace-архів (опція trace: 'on-first-retry' записує трейс лише для повторного прогону впалого тесту). Trace viewer дає снапшот DOM на кожному кроці, мережу й консоль — це найбагатший контекст, який можна віддати AI для розбору (детальніше про сам trace viewer — у розділі про інструменти автоматизації). Ключове: згодовуйте AI факти прогону, а не свій переказ. Ваш переказ уже містить вашу гіпотезу, і модель радо на неї «приякорюється».
Фейл ≠ баг: де AI помиляється в діагнозі
Найважливіша ідея всього супроводу: падіння тесту не дорівнює баг застосунку. Червоний прогон має рівно три причини, і плутати їх дорого:
- Баг продукту — застосунок справді працює неправильно. Це те, заради чого тест існує.
- Баг тесту — крихкий локатор, забутий
await, гонка в самому тесті, застарілий крок після зміни UI. Продукт здоровий. - Інфраструктура / флак — оточення моргнуло, впав сусідній сервіс, тест-дані зайняв інший воркер.
Ця класифікація — канон флакі-тестів (розділ «Автоматизація: стратегія», глава про флакі) і наскрізна тема співбесід; браузерну механіку того, чому UI-тест бачить «не той» стан, розібрано в главі Практичні сценарії AQA: флак і синхронізація.
Тепер про те, як саме AI тут помиляється. Модель дає найправдоподібніший діагноз, а не найправильніший, і в неї є впізнавані патерни хиб:
- Приякорення до симптому. Бачить
Timeout— радить збільшити таймаут. Але таймаут спливає і коли елемента немає через реальний баг, і коли тест чекає не на те. «Збільш таймаут» замасковує гонку замість полагодити її. - Звинувачення застосунку за замовчуванням. AI охоче пише «схоже, у застосунку баг», бо це правдоподібна фраза — навіть коли винен крихкий тест. Для QA це найдорожча помилка: завести баг на здоровий продукт означає спалити довіру команди.
- Вигаданий root cause, що пасує до симптому. Модель сконструює зв'язну причинну історію, яка ідеально пояснює лог і при цьому не має нічого спільного з реальністю. Гладкість тексту не корелює з правильністю — це та сама пастка, що й у главі Верифікація результатів AI.
Практичне правило: AI генерує гіпотези, підтверджуєте їх ви — повторним прогоном, ручним відтворенням кроку, зазиранням у мережу чи БД. Гіпотеза «це баг бекенду» коштує один запит curl для перевірки; не перевіряти її й одразу заводити дефект — антипатерн.
Флакі: аналіз патернів
Ось де AI приносить найбільше чесної користі. Один флакі-фейл людина розбере й сама. А от патерн у сотні прогонів око не бачить — і саме тут модель сильна: згодуйте їй історію падінь (які тести, коли, на яких воркерах, у якому оточенні), і попросіть згрупувати за спільними ознаками.
Типові патерни, які так виринають:
- тест червоніє лише вночі → майже завжди таймзона чи межа доби в даних;
- падає лише на воркері N при паралельному запуску → спільні тест-дані, конфлікт за одним акаунтом;
- зелений локально, червоний лише в CI → headless-таймінги, повільніше оточення, інший стан кешу (див. Кешування);
- серія тестів валиться після одного конкретного → протікання стану, порушена ізоляція.
Чому це працює: LLM добре підсумовує й кластеризує накидані дані. Але межу треба тримати чітко: AI групує симптоми, а не встановлює причину. «Ці п'ять тестів падають на воркері 3» — це кластер, а не діагноз; чому саме воркер 3, з'ясовуєте ви. Модель дає напрямок пошуку й економить години читання логів — не готовий вирок.
Рефакторинг тестів з AI
Супровід — це ще й переписування старого коду, і тут AI сильний, бо більшість рефакторингу — механічні трансформації, які легко перевірити прогоном і diff-ом. Витягнути повторюваний блок у page object, прибрати дублювання, перейменувати, замінити застарілий патерн на сучасний — усе це модель робить швидко й здебільшого коректно.
Класичний приклад — масова заміна хардкодних очікувань на web-first асерти:
// Було: хардвейт — антипатерн, тримає флак і гальмує прогін
await page.waitForTimeout(3000);
expect(await page.locator('.status').textContent()).toBe('Готово');
// Стало: web-first асерт з авторетраєм, чекає рівно скільки треба
await expect(page.locator('.status')).toHaveText('Готово');
Чому такий рефакторинг відносно безпечний для AI: результат детермінований і перевірюваний — тест або проходить після зміни, або ні, а diff видно очима. Але «відносно» не означає «сліпо». Модель може при рефакторингу непомітно послабити перевірку (замінити точну асерцію на присутність елемента) або втратити крайовий випадок. Тому будь-який AI-рефакторинг проходить ту саму верифікацію, що й будь-який AI-вивід: прочитати diff критично, прогнати, і — головне — переконатися, що тест досі червоніє, коли фічу зламано (див. Верифікація результатів AI).
Self-healing локатори і їхні ризики
Self-healing локатори (самовідновні локатори) — це механізм, коли тестовий інструмент, не знайшовши елемент за основним селектором, не падає одразу, а намагається знайти «той самий» елемент за іншими ознаками (текст, ARIA-роль, сусідні вузли, позиція) і продовжити прогін. Це фіча низки комерційних платформ (Testim, Mabl, testRigor) і опенсорсних надбудов (Healenium для Selenium); у Playwright «з коробки» такого немає — там ставку зроблено на стабільні локатори за замовчуванням.
Спокуса зрозуміла: після кожної зміни верстки менше червоних білдів, менше ручної правки локаторів. Але для QA тут ховається концептуальний конфлікт, і його треба вміти сформулювати на співбесіді:
Сенс тесту — впасти, коли застосунок несподівано змінився. Self-healing прямо цьому протидіє. Якщо кнопку «Оплатити» перейменували на «Купити», це могло бути свідоме рішення продукту — а могла бути й регресія. Самовідновлення тихо «підлікує» локатор і зробить білд зеленим в обох випадках, і другий — це пропущений баг під виглядом успіху.
Конкретні ризики:
- Маскування регресій — елемент зник чи змінився через баг, а тест «загоївся» на схожий і не помітив.
- Загоєння на неправильний елемент — на сторінці дві схожі кнопки, евристика вибрала не ту; тест зелений, але перевіряє не те.
- Недетермінізм — рішення про «схожість» імовірнісне, тож той самий тест може лікуватися по-різному в різних прогонах, додаючи новий шар флаку замість прибрати старий.
- Тихий дрейф — локатори повільно розходяться з реальним DOM, і ніхто цього не бачить, доки все не розсиплеться разом.
Здорова позиція: self-healing прийнятний як підказка для людини («локатор ось-ось зламається, ось кандидат на заміну — підтвердь»), а не як тихе автопродовження зеленим. Фундамент усе одно той самий, що й без AI — стабільні локатори (data-testid, ARIA-ролі) як контракт із розробкою; це канон стратегії локаторів у розділі автоматизації, а механіку селекторів розібрано в главі DOM, селектори та події.
Оновлення тестів після зміни UI/API
Коли фіча свідомо змінилася, десятки тестів червоніють законно — їх треба привести у відповідність. AI тут прискорює, але за однієї умови: давайте йому diff зміни, а не змушуйте вгадувати. Модель не бачила ні старого, ні нового застосунку; здогад «як тепер виглядає форма» — це вигадка. А от diff PR-у застосунку, зміна в OpenAPI-специфікації чи DOM «до/після» — це факти, з якими вона працює предметно.
- Зміна API. Згодуйте diff OpenAPI або приклад нової відповіді — і модель оновить асерти на тіло, статуси, назви полів. Тут доречні контрактні перевірки схемою (валідація структури програмно), а не звірка полів очима.
- Зміна UI. Новий
data-testid, переміщений елемент, перейменована дія — з diff-ом розмітки AI оновить локатори й кроки швидко.
Але є критична пастка, за яку карають на співбесіді. AI з радістю «полагодить» тест так, щоб він проходив під новий стан застосунку — навіть якщо цей стан і є регресією. Оновити впалий тест, щоб він позеленів, і закрити тікет — найлегший шлях зробити баг невидимим. Рішення «нова поведінка правильна» чи «це баг» — не технічне й не для моделі; його ухвалює людина за вимогами. AI прибирає механічну рутину оновлення; питання інтенту лишається за вами.
AI-рев'ю в пул-реквесті
AI-рев'ю (від вбудованого в термінальний агент до ботів, що коментують пул-реквести) працює у двох напрямках: рев'ю вашого тестового PR і рев'ю продуктового PR з погляду QA. У супроводі корисні обидва.
Що AI ловить добре — це механічні дефекти й запахи, які око проскакує на великому diff:
- забутий
awaitперед web-first асертом; - тавтологічні перевірки на кшталт
expect(true).toBeTruthy(); - хардвейти замість авторетраю;
- крихкі локатори за згенерованими класами;
- відсутність негативних сценаріїв там, де вони очевидні.
Чого AI не ловить — і чому він не заміняє людину-рев'юера: чи перевіряє тест правильний інваріант, чи відповідає очікуваний результат реальній вимозі, чи має зміна доменний сенс. Модель бачить форму коду, не його намір. Тому найнебезпечніший результат — зелене AI-рев'ю сприймають як гарантію якості: бот не знайшов зауважень, отже все добре. Ні: відсутність механічних зауважень не означає, що тести перевіряють те, що треба. AI-рев'ю — це швидкий перший фільтр, який знімає рутину з людини-рев'юера, а не gate, що її замінює; фінальне слово на PR лишається за інженером (інтеграцію таких перевірок у пайплайн розібрано в розділі про Git і CI/CD).
Типові помилки
- AI сказав «це баг застосунку» — виглядає як готовий діагноз, а насправді модель за замовчуванням звинувачує продукт; часто винен крихкий тест або флак, і перевірити треба руками до заведення дефекту.
Timeout→ «збільш таймаут» — виглядає як фікс, а насправді таймаут маскує гонку чи реальну відсутність елемента; більший таймаут лише повільніше валиться.- Self-healing зробив білд зеленим — виглядає як стабільність, а насправді тест міг «загоїтися» на неправильний елемент або приховати регресію; сенс тесту — впасти на несподівану зміну.
- AI оновив упалий тест, він проходить — виглядає як приведення у відповідність, а насправді тест міг бути підігнаний під баг; правильність нової поведінки вирішують вимоги, не модель.
- Зелене AI-рев'ю в PR — виглядає як знак якості, а насправді бот перевіряє форму, а не те, чи тест ловить правильний інваріант.
- Кинув голий лог, отримав причину — виглядає як тріаж, а насправді без trace/скриншота/мережі це вгадування; діагноз рівно такий, як контекст.
Підсумок
- AI у тріажі корисний рівно настільки, наскільки повний контекст: давайте йому артефакти прогону (trace, скриншот, мережу, стек), а не власний переказ із уже вбудованою гіпотезою.
- Червоний тест — це три різні речі: баг продукту, баг тесту, інфраструктура/флак. AI генерує гіпотезу; класифікацію підтверджуєте ви.
- Модель схильна приякорюватися до симптому, звинувачувати застосунок і вигадувати зв'язний, але хибний root cause — гладкість діагнозу не є його правильністю.
- Self-healing локатори борються з самою метою тесту — падати на несподівану зміну; прийнятні як підказка людині, не як тихе автозагоєння зеленим.
- AI прибирає механічну рутину рефакторингу, оновлення й рев'ю, але рішення про інтент («нова поведінка правильна чи це баг») і фінальний gate лишаються за інженером.
Що питають на співбесіді
- «Тест упав. Як ви користуєтесь AI, щоб розібратися?» — інтерв'юер хоче почути про збір контексту (trace, скриншот, мережа, логи), а не «кидаю лог — він каже причину». Сильна відповідь згадує, що AI дає гіпотезу, яку ви перевіряєте.
- «AI сказав, що це баг застосунку. Що робите далі?» — пастка на різницю фейл ≠ баг. Правильно: не заводжу дефект наосліп, спершу відтворюю руками / перевіряю бекенд, класифікую баг тесту vs баг продукту vs флак.
- «Що думаєте про self-healing локатори?» — перевірка зрілості. Очікують названий конфлікт: самовідновлення суперечить меті тесту падати на зміну; ризик маскування регресій і загоєння на не той елемент; прийнятно лише як підказка.
- «AI переписав/оновив тест, він зелений. Мержимо?» — перевірка на автоматизаційне упередження. Сильна відповідь: спершу переконуюся, що тест червоніє при зламаній фічі, і що оновлення не підігнане під регресію.
- «Чи можна довіряти AI-рев'ю в PR замість людини?» — очікують межу: AI ловить механічні дефекти й запахи, але не доменну коректність та інваріант; це фільтр, не gate.
На що дивиться інтерв'юер: чи трактуєте ви AI-діагноз як гіпотезу на перевірку, а не як вирок; чи тримаєте різницю «фейл тесту ≠ баг продукту»; чи усвідомлюєте, що зелене (загоєний локатор, оновлений тест, чисте AI-рев'ю) не дорівнює правильному.
Джерела
- ISTQB Certified Tester Foundation Level (CTFL) v4.0 — базові поняття: різниця помилка/дефект/збій, хибнопозитивні та хибнонегативні результати тестів — теоретичне підґрунтя принципу «фейл ≠ баг».
- ISTQB Certified Tester AI Testing (CT-AI) — охоплює як тестування AI-систем, так і використання AI в самому тестуванні; корисний для розуміння меж і ризиків AI-інструментів у супроводі.
- Playwright — Trace Viewer — офіційна документація про trace як найбагатший артефакт падіння: дії, DOM-снапшоти, мережа, консоль.
- Playwright — Best Practices — чому web-first асерти й стабільні локатори, а
waitForTimeout— антипатерн; фундамент для рефакторингу супроводу.
Що таке тріаж червоного прогону і чому якість AI-діагнозу впирається саме в контекст?
Тріаж (triage) — первинне сортування впалих тестів: швидко зрозуміти, що зламалося й куди копати, ще до глибокого розбору. AI не має власного доступу ні до вашого CI, ні до екрана, ні до стану бекенду — він працює виключно з тим шматком тексту, який ви вставили в промпт. Тому діагноз виходить рівно такої якості, як набір фактів, що ви передали: одне слово «таймаут» дасть здогад, а trace із мережею й DOM — предметний напрямок. Порівняння просте: просити модель назвати причину за голим рядком помилки — те саме, що вимагати діагноз від лікаря за реплікою «болить». На співбесіді middle-рівня тут і видно слабкого кандидата: «кидаю лог, він каже причину» звучить як тріаж, а насправді це вгадування.
Які артефакти падіння варто передавати AI і чому голого повідомлення помилки замало?
Повідомлення помилки — лише верхівка: воно каже тип винятку й рядок, але не показує, що було на екрані й чи взагалі дійшов запит до бекенду. Інформативний набір складають стек-трейс (який виклик упав), локатор, що не зматчився (чого тест не знайшов на сторінці), скриншот моменту падіння (реальний стан екрана), trace або відео (послідовність кроків, мережа, консоль, DOM-снапшоти), HAR мережевих запитів (чи прийшла відповідь, який статус, що в тілі) і серверні логи (виняток на бекенді, correlation id). Найбагатший з них — trace: він єдиний зшиває дію, стан сторінки й мережу в одну картину. У Playwright цей архів збирається автоматично, наприклад опцією trace: 'on-first-retry', яка пише трейс лише для повторного прогону впалого тесту. Що ширший контекст, то менше моделі лишається домислювати.
Чому не варто давати AI власний переказ падіння замість сирих фактів прогону?
Бо переказ уже несе вашу гіпотезу, а модель охоче до неї приякорюється й підтверджує те, що ви й так підозрювали. Напишете «впав, бо бекенд віддав не те» — AI підхопить рамку й будуватиме пояснення навколо неї, навіть якщо насправді винен крихкий локатор. Сирий артефакт (стек, trace, HAR) такого упередження не містить: він змушує модель відштовхуватися від того, що реально сталося, а не від вашої версії. Практичний висновок: у промпт кладіть факти прогону, а власний здогад лишайте наостанок або взагалі притримайте, поки не побачите незалежну гіпотезу. Це той самий порядок, що й у ручному тріажі, — спершу спостереження, потім висновок.
Червоний тест має три різні причини. Назвіть їх і поясніть, чому їх дорого плутати.
Падіння тесту означає одне з трьох, і кожне лікується інакше. Перше — баг продукту: застосунок справді працює неправильно, і саме заради цього тест існує. Друге — баг тесту: крихкий локатор, забутий await, гонка в самому коді тесту, застарілий крок після зміни UI; продукт при цьому здоровий. Третє — інфраструктура або флак: моргнуло оточення, впав сусідній сервіс, тестові дані перехопив паралельний воркер. Плутати їх дорого, бо реакції протилежні: на баг продукту заводять дефект, баг тесту чинять у своєму коді, а флак стабілізують ізоляцією й ретраями. Найдорожча помилка — завести дефект на здоровий продукт: це спалює довіру команди до всього набору тестів.
Як саме AI помиляється, коли ставить діагноз падінню?
Модель видає найправдоподібніший текст, а не найправильніший, і має три впізнавані патерни хиб. Приякорення до симптому: побачивши Timeout, вона радить збільшити таймаут, хоча час спливає і при реальній відсутності елемента, і коли тест чекає не на те. Звинувачення застосунку за замовчуванням: фраза «схоже, у продукті баг» правдоподібна, тож AI пише її навіть тоді, коли винен тест. Вигаданий root cause: модель конструює зв'язну причинну історію, яка ідеально пояснює лог і водночас не має нічого спільного з реальністю. Спільний корінь усіх трьох — гладкість формулювання не корелює з його правильністю. Тому AI-діагноз завжди трактують як гіпотезу на перевірку, а не як вирок.
AI побачив Timeout і радить збільшити таймаут. Чому це небезпечна порада?
Бо таймаут — це симптом із кількома різними причинами, а більший ліміт лікує лише одну з них. Час спливає, коли елемент реально не з'явився через баг продукту, коли тест чекає не на той стан через гонку в собі, і коли оточення просто повільне. У перших двох випадках збільшення таймауту нічого не чинить — воно лише змушує тест валитися повільніше, зате маскує справжню проблему під виглядом «стабілізації». Особливо шкідливо це з гонкою: замість перейти на web-first очікування правильного стану команда роздуває таймаут, і флак повертається за кілька тижнів. Правильна реакція — з'ясувати, чого саме тест не дочекався, а не наосліп додавати секунди.
Де в аналізі флаку AI приносить найбільше чесної користі?
У пошуку патерну по великому масиву падінь, який людське око не охоплює. Один флакі-фейл інженер розбере й сам, а от закономірність у сотні прогонів — які тести, коли, на яких воркерах, у якому оточенні — руками не побачиш. Тут LLM сильна за своєю природою: вона добре підсумовує й кластеризує накидані дані, тож згодуйте їй історію падінь і попросіть згрупувати за спільними ознаками. На виході — напрямок пошуку: «ці п'ять валяться разом на одному воркері», «ця група червоніє тільки вночі». Це економить години читання логів, але саме напрямок, а не готовий вирок — межу треба тримати чітко.
Тест червоніє лише вночі, лише на воркері N або лише в CI. Про що зазвичай сигналить кожен патерн?
Це класичні кластери, кожен зі своїм типовим коренем. «Лише вночі» майже завжди вказує на таймзону чи межу доби в даних — тест переступає північ або рахує «сьогодні» не в тому поясі. «Лише на воркері N при паралельному запуску» — конфлікт за спільними тест-даними: два потоки правлять один акаунт чи запис. «Зелений локально, червоний лише в CI» — headless-таймінги, повільніше оточення, інший стан кешу. «Серія тестів валиться після одного конкретного» — протікання стану й порушена ізоляція: попередній тест лишив по собі сміття. Важливий нюанс: усе це кластери-підказки, а не діагнози — чому саме воркер 3 чи саме ніч, доводите ви перевіркою.
Чому кажуть, що AI групує симптоми, а не встановлює причину?
Бо кластеризація — це спостереження про форму падінь, а не доведений причинно-наслідковий зв'язок. «Ці тести падають на воркері 3» — правдиве угруповання, але воно не пояснює, чому саме там: спільний акаунт, конфлікт портів, брак ресурсів на цій машині — версій багато. Модель бачить кореляцію в даних, які ви їй дали, і чесно її називає, проте механізм за кореляцією вона не перевіряла й перевірити не може. Якщо прийняти кластер за причину, полагодите не те й патерн повернеться. Тому AI дає напрямок розкопок, а сам діагноз ви підтверджуєте — повторним прогоном, читанням логів воркера, зазиранням у дані.
Чому рефакторинг тестів вважають відносно безпечною задачею для AI?
Бо більшість рефакторингу — механічні трансформації з детермінованим і перевірюваним результатом. Витягнути повторюваний блок у page object, прибрати дублювання, перейменувати, замінити застарілий патерн на сучасний — тут тест або проходить після зміни, або ні, а diff видно очима. Класика — масова заміна хардвейтів на web-first асерти: await page.waitForTimeout(3000) перед перевіркою тексту перетворюється на await expect(locator).toHaveText(...) з авторетраєм. Petля зворотного зв'язку коротка: прогнав набір, подивився diff — і одразу ясно, чи не зламалося. Саме ця перевірюваність робить задачу зручною для моделі, на відміну від питань інтенту, де правильної відповіді в самому коді немає.
Який головний ризик AI-рефакторингу асертів, навіть якщо тест після нього зелений?
Модель може непомітно послабити перевірку — і зелений колір це замаскує. Типово: замість точної асерції на текст чи значення AI ставить перевірку на саму присутність елемента, або втрачає крайовий випадок, який покривала стара версія. Тест проходить, diff виглядає чистим, але він тепер ловить менше, ніж ловив. «Відносно безпечно» не означає «сліпо мержити»: будь-який AI-рефакторинг проходить ту саму верифікацію, що й решта AI-виводу. Ключова перевірка — переконатися, що тест досі червоніє, коли фічу навмисно зламати; зелений на робочій фічі нічого не гарантує, якщо він зелений і на зламаній.
Що таке self-healing локатори і як вони працюють?
Self-healing локатори (самовідновні локатори) — механізм, коли інструмент, не знайшовши елемент за основним селектором, не падає одразу, а намагається знайти «той самий» елемент за іншими ознаками (текст, ARIA-роль, сусідні вузли, позиція) і продовжити прогін. Ідея — менше червоних білдів і ручної правки локаторів після кожної зміни верстки. Це фіча низки комерційних платформ (Testim, Mabl, testRigor) та опенсорсних надбудов на кшталт Healenium для Selenium. У Playwright такого «з коробки» немає: там ставку зроблено на стабільні локатори за замовчуванням, а не на автовідновлення крихких. Рішення про «схожість» тут завжди евристичне, тобто імовірнісне.
Який концептуальний конфлікт між self-healing і самою метою тесту?
Сенс тесту — впасти, коли застосунок несподівано змінився; self-healing прямо цьому протидіє. Уявіть, що кнопку «Оплатити» перейменували на «Купити»: це могло бути свідоме рішення продукту, а могла бути й регресія. Самовідновлення тихо «підлікує» локатор і зробить білд зеленим в обох випадках — і в другому це пропущений баг під виглядом успіху. Тобто механізм прибирає рівно той сигнал, заради якого тест писали. На співбесіді очікують, що кандидат назве цей конфлікт словами, а не просто скаже «self-healing зручний»: зручність і є пасткою, бо вона купується ціною сліпоти до змін.
Назвіть конкретні ризики self-healing локаторів.
Їх чотири, і всі про приховану деградацію. Маскування регресій: елемент зник чи змінився через баг, а тест «загоївся» на схожий і нічого не помітив. Загоєння на неправильний елемент: на сторінці дві схожі кнопки, евристика вибрала не ту — тест зелений, але перевіряє не те. Недетермінізм: рішення про схожість імовірнісне, тож той самий тест може лікуватися по-різному в різних прогонах, додаючи новий шар флаку замість прибрати старий. Тихий дрейф: локатори повільно розходяться з реальним DOM, ніхто цього не бачить, доки все не розсиплеться разом. Спільна риса — усі чотири ховаються за зеленим кольором, тому їх важко зловити без окремого контролю.
Як тоді можна вбудувати self-healing, щоб він не шкодив?
Прийнятна форма — підказка людині, а не тихе автопродовження зеленим. Тобто інструмент має право сказати «локатор ось-ось зламається, ось кандидат на заміну — підтвердь», але не має права мовчки перемкнутися на інший елемент і зарахувати білд як успішний. У першому випадку рішення лишається за інженером, який звірить кандидата з реальністю; у другому механізм сам виносить вирок, до якого не має компетенції. Фундамент при цьому той самий, що й без AI, — стабільні локатори (data-testid, ARIA-ролі) як контракт із розробкою. Self-healing у здоровій конфігурації доповнює цей контракт сигналом про дрейф, а не заміняє його евристикою.
Як AI прискорює оновлення тестів після зміни UI чи API і за якої умови?
Коли фіча свідомо змінилася, десятки тестів червоніють законно, і привести їх у відповідність — механічна рутина, з якою модель справляється швидко. Умова одна: давати їй diff зміни, а не змушувати вгадувати. Модель не бачила ні старого, ні нового застосунку, тож здогад «як тепер виглядає форма» — чиста вигадка. А от diff PR-у, зміна в OpenAPI-специфікації чи розмітка «до/після» — це факти, з якими вона працює предметно. На зміні API згодуйте новий приклад відповіді або diff схеми — і AI оновить асерти на статуси, тіло, назви полів (тут доречні контрактні перевірки схемою, а не звірка полів очима). На зміні UI новий data-testid чи переміщений елемент з diff-ом розмітки оновлюються так само швидко.
Яка головна пастка при оновленні впалого тесту руками AI?
AI з радістю «полагодить» тест так, щоб він проходив під новий стан застосунку, — навіть якщо цей стан і є регресією. Оновити впалий тест до зеленого й закрити тікет — найлегший спосіб зробити баг невидимим: перевірка тепер узгоджена зі зламаною поведінкою й більше на неї не скаржиться. Рішення «нова поведінка правильна» чи «це баг» не технічне й не для моделі — його ухвалює людина за вимогами продукту. AI знімає механічну частину (переписати локатори, підправити асерти), але питання інтенту лишається за інженером. Тому оновлений тест обов'язково звіряють із вимогою, а не просто радіють, що він позеленів.
Що AI-рев'ю в пул-реквесті ловить добре, а що — принципово ні?
Добре ловить механічні дефекти й запахи, які око проскакує на великому diff: забутий await перед web-first асертом, тавтологічні перевірки на кшталт expect(true).toBeTruthy(), хардвейти замість авторетраю, крихкі локатори за згенерованими класами, відсутність очевидних негативних сценаріїв. Це швидкий перший фільтр, що знімає рутину з людини-рев'юера. Чого AI не бачить: чи перевіряє тест правильний інваріант, чи відповідає очікуваний результат реальній вимозі, чи має зміна доменний сенс. Модель читає форму коду, а не його намір. Тому AI-рев'ю працює як фільтр, а не як gate, і фінальне слово на PR лишається за інженером.
Чому «зелене AI-рев'ю» небезпечно трактувати як гарантію якості?
Бо відсутність механічних зауважень і коректність тесту — це різні речі. Бот не знайшов забутих await і крихких локаторів — це означає лише, що форма коду чиста, а не що тест перевіряє те, що треба. Тест може бути бездоганний синтаксично й водночас асертити не той інваріант, звірятися з хибним очікуванням чи взагалі не мати доменного сенсу — усе це AI-рев'ю пропустить. Найгірший сценарій, коли команда сприймає зелений вердикт бота як «якість підтверджено» й вимикає людський розбір. Правильна рамка: чисте AI-рев'ю прибирає шум і економить час рев'юера, але не переносить на нього відповідальність — її несе інженер, що апрувить PR.
Сформулюйте загальне правило роботи з будь-яким AI-діагнозом у супроводі тестів.
AI генерує гіпотези — підтверджуєте їх ви. Хоч що модель сказала про падіння, флак, рефакторинг чи оновлення тесту, це кандидат на перевірку, а не встановлений факт: гіпотезу «це баг бекенду» коштує один curl відтворити, а не перевірити її й одразу завести дефект — антипатерн. Наскрізна дисципліна — розрізняти форму й суть: гладкий діагноз не дорівнює правильному, зелений колір (загоєний локатор, оновлений тест, чисте рев'ю) не дорівнює правильному тесту. Практично це означає завжди зводити AI-вивід до перевірюваної дії: повторний прогін, ручне відтворення кроку, зазирання в мережу чи БД, перевірка, що тест червоніє на зламаній фічі. AI прибирає рутину, але класифікацію, інтент і фінальний gate тримає інженер.
Три ситуації супроводу, де AI або економить годину тріажу, або впевнено веде не туди: як один і той самий промпт міняє діагноз залежно від контексту, як класифікувати падіння замість вірити «це баг застосунку», і як self-healing локатор перетворює регресію на зелений білд. Скрізь — що дивитися і де межа довіри.
Кейс 1. Один фейл, два промпти: чому контекст вирішує все
Уранці впав тест оформлення замовлення. Помилка сама по собі скупа:
TimeoutError: locator.click: Timeout 30000ms exceeded.
Call log:
- waiting for getByRole('button', { name: 'Оплатити' })
Поганий промпт — кинути AI рівно цей рядок і спитати «чому впало». Модель відповість найправдоподібнішим текстом: «схоже, кнопка вантажиться повільно — збільште таймаут» або «ймовірно, баг у застосунку, кнопка не відрендерилась». Обидва діагнози звучать гладко й обидва можуть бути хибними: жодного факту про реальний стан екрана в промпті не було, тож це вгадування, а не тріаж.
Хороший промпт — додати артефакти прогону з trace. Тоді в контексті з'являються мережа й DOM-снапшот моменту падіння:
Network (з trace):
POST /api/cart/checkout → 200 OK
GET /api/user/profile → 401 Unauthorized
DOM-снапшот на момент падіння:
<div class="session-expired-modal">Сесія завершилася. Увійдіть знову.</div>
Тепер картина інша: кнопки «Оплатити» немає не тому, що вона повільна, а тому що поверх сторінки — модалка простроченої сесії через 401. Збільшення таймауту тут не допомогло б ніколи. AI з таким контекстом дасть предметну гіпотезу («токен протух до кроку оплати»), яку легко перевірити.
Що дивитися і чому:
- Голе повідомлення помилки несе тип і рядок, але не стан екрана.
Timeoutна кліку однаково виглядає і коли елемент повільний, і коли його перекрила модалка, і коли його взагалі немає через баг. Розрізняє ці випадки саме DOM-снапшот і мережа з trace. 401у мережі — це напрямок, а не вирок. Він каже, куди копати (автентифікація перед оплатою), але чому саме протух токен — короткий TTL, гонка з рефрешем, кривий сетап тесту — з'ясовуєте ви. AI звузив пошук з усієї сторінки до одного запиту; діагноз усе одно за вами.- Переказ отруює діагноз. Якби в промпті було «кнопка оплати не завантажується, здається, баг рендеру», модель приякорилась би до рендеру й могла б не помітити
401. Сирий trace такого упередження не має.
Кейс 2. «AI сказав, що це баг застосунку» — класифікація по кроках
Частий ранковий діалог: інженер кинув боту лог 500, той відповів «схоже на баг бекенда», і виникає спокуса завести дефект і закрити тікет. Але 5xx міг тригернути будь-хто, тож спершу — класифікація. Таблиця рішень для трьох причин червоного:
| Спостереження | Імовірна причина | Перша перевірка |
|---|---|---|
500 відтворюється валідним запитом через curl | Баг продукту | Стектрейс у логах сервера → який контролер упав |
500 не відтворюється руками, падає лише тест | Баг тесту | Що реально пішло в запиті: токен, змінна, середовище |
Масові 502/503/504 одразу після релізу | Інфра/деплой | Чи середовище взагалі піднялося |
Зелено поодинці, 500 лише під паралелізмом | Флак/ізоляція | Спільні дані, гонки, rate limit між воркерами |
Найдешевша перевірка — відтворити той самий запит руками, а не вірити на слово:
# той самий виклик, що впав у тесті — валідним запитом
curl -i -X POST https://staging.example.com/api/orders \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"productId": 42, "qty": 1}'
- Відтворюється валідним запитом → кандидат на баг бекенда, і стектрейс у логах це підтвердить.
- Не відтворюється, а тест усе одно падає → підозра зміщується на тест: не підставилась змінна, протух токен, крива фікстура, не те середовище.
Що дивитися і чому:
- AI звинувачує застосунок за замовчуванням. «Схоже на баг продукту» — правдоподібна фраза, яку модель пише й тоді, коли винен крихкий тест. Це найдорожча помилка тріажу: дефект на здоровий продукт палить довіру команди.
- Гіпотеза коштує один
curl. Заявляти причину без перевірки — антипатерн; «стектрейс указує на конкретний контролер» варте рівно стільки, скільки під ним доказів. 500на завідомо кривому вводі — окремий дефект бекенда. Навіть якщо тригер прийшов від тесту, добре спроєктований сервер мав відповісти400/422, а не впасти. Тобто винних тут може бути двоє одночасно.
Кейс 3. Self-healing проти стабільного локатора: як регресія стає зеленою
Розробники перейменували кнопку кошика й заразом випадково прибрали в неї обробник кліку — покупку зламано. Дивимось, як на це реагують два підходи.
import { test, expect } from '@playwright/test';
// Стабільний локатор: контракт із розробкою через data-testid
test('кнопка "Купити" додає товар у кошик', async ({ page }) => {
await page.goto('https://shop.example.com/product/42');
await page.getByTestId('add-to-cart').click();
await expect(page.getByTestId('cart-badge')).toHaveText('1');
});
Якщо data-testid на місці, але обробник зник — тест чесно червоніє на асерті cart-badge: лічильник кошика лишився 0. Це і є сенс тесту — впасти на несподівану зміну поведінки. Регресію спіймано до продакшену.
Тепер уявімо той самий сценарій під платформою із self-healing, де локатор прив'язаний до тексту кнопки:
Крок: click button "Додати в кошик"
⚠ основний селектор не знайдено (кнопку перейменували на "Купити")
✓ self-healing: знайдено схожий елемент за роллю/позицією → "Купити"
✓ клік виконано, крок пройдено
Результат білда: PASSED
Локатор «загоївся», клік формально відбувся — але обробник зламано, товар у кошик не потрапив, а білд зелений. Самовідновлення прибрало рівно той сигнал, заради якого тест існував.
Що дивитися і чому:
- Self-healing протидіє меті тесту. Перейменування кнопки могло бути свідомим рішенням продукту, а могло бути регресією; механізм робить білд зеленим в обох випадках, і другий — це пропущений баг під виглядом успіху.
- Загоєння буває на неправильний елемент. Якби поруч була ще одна кнопка, евристика могла вибрати не ту — тест лишався б зеленим, перевіряючи не те. Рішення про «схожість» імовірнісне, тож ще й недетерміноване між прогонами.
- Здорова конфігурація — підказка, не автопродовження. Прийнятний варіант: «локатор ось-ось зламається, кандидат на заміну — "Купити", підтвердь». Тоді інженер звірить зміну з вимогою, а не бот винесе вирок, до якого не має компетенції.
- Фундамент той самий, що й без AI. Стабільні локатори (
data-testid, ARIA-ролі) як контракт із розробкою надійніші за будь-яку евристику схожості; self-healing у кращому разі доповнює їх сигналом про дрейф, а не заміняє.
Тріаж і контекст для AI
- Розумію, що AI не бачить мого CI, екрана й бекенду — його діагноз рівно такий, як факти, вставлені в промпт.
- Знаю набір інформативних артефактів падіння: стек-трейс, локатор, що не зматчився, скриншот, trace/відео, HAR, серверні логи.
- Можу пояснити, чому trace — найбагатший артефакт: він зшиває дію, стан DOM і мережу в одну картину.
Фейл ≠ баг
- Тримаю три причини червоного тесту: баг продукту, баг тесту, інфраструктура/флак — і знаю, що реакція на кожну різна.
- Розумію, чому завести дефект на здоровий продукт — найдорожча помилка: вона палить довіру команди до тестів.
- Знаю три патерни хиб AI: приякорення до симптому, звинувачення застосунку за замовчуванням, вигаданий root cause.
- Тримаю правило: AI дає гіпотезу, класифікацію підтверджую я — повторним прогоном, ручним відтворенням,
curlдо бекенду.
Флакі та патерни
- Розумію, де AI сильний у флаку: кластеризація патерну по сотні прогонів, який око не охоплює.
- Знаю типові кластери: «лише вночі» → таймзона, «воркер N» → спільні дані, «лише в CI» → headless-таймінги, «після одного тесту» → протікання стану.
- Можу пояснити межу: AI групує симптоми, а причину за кластером доводжу я.
Рефакторинг і оновлення тестів
- Розумію, чому механічний рефакторинг відносно безпечний для AI: результат детермінований і перевірюваний diff-ом та прогоном.
- Пам'ятаю ризик: AI може непомітно послабити асерцію — тому перевіряю, що тест досі червоніє на зламаній фічі.
- Можу пояснити умову оновлення тестів: давати AI diff зміни (PR, OpenAPI, DOM «до/після»), а не змушувати вгадувати.
- Тримаю пастку: AI підганяє впалий тест під новий стан навіть якщо той стан — регресія; рішення про інтент за людиною.
Self-healing локатори
- Формулюю конфлікт: мета тесту — впасти на несподівану зміну, а self-healing тихо це загоює.
- Знаю чотири ризики: маскування регресій, загоєння на не той елемент, недетермінізм, тихий дрейф локаторів.
- Тримаю здорову позицію: self-healing прийнятний як підказка людині, не як тихе автопродовження зеленим.
AI-рев'ю в PR
- Знаю, що AI-рев'ю ловить: забутий
await, тавтології, хардвейти, крихкі локатори, брак очевидних негативних сценаріїв. - Розумію, чого воно не ловить: правильність інваріанта, відповідність вимозі, доменний сенс.
- Можу пояснити, чому зелене AI-рев'ю — не гарантія якості, а лише фільтр, і чому фінальний gate лишається за інженером.
Від чого насамперед залежить якість AI-діагнозу впалого тесту?
Питання
Тріаж (triage) падіння — що це і чому для AI критичний контекст?