07 · Інструменти автоматизації
Playwright: дебаг, trace viewer і репортинг
Зміст
Червоний тест у CI — це не повідомлення про баг, а квиток на розслідування. Локально в тебе є браузер під рукою: можна поставити паузу, поклацати, подивитися DOM. У CI немає нічого, крім файлів, які прогін по собі лишив, — і саме там падає та частина тестів, яка «локально ж проходила». Тому інструмент дає два різні класи засобів: живі (Inspector, UI mode) і post-mortem-засоби (trace viewer), де ти читаєш запис уже завершеного прогону. Плюс третій шар — репортери, які перетворюють прогін у щось придатне для читання людиною і машиною.
Цю главу можна пропустити при першому проході: щоб писати тести, вона не потрібна. Але тут закінчуються питання «а чому в CI падає, а локально ні» — і починається різниця між «перезапустив, і воно позеленіло» та «знаю, на якій дії, з яким локатором і чому». Таксономія падінь, політика і звітність як дисципліна живуть у розділі «Автоматизація тестування»; тут — механіка конкретного інструмента.
Два режими: наживо і після факту
Inspector — це GUI, у якому тест виконується покроково: видно поточну дію, можна правити наживо, підбирати локатори й читати логи придатності до дії (actionability). Відкривається прапорцем --debug.
Головне про цей розуміють не одразу: він не просто відкриває вікно, а міняє конфігурацію прогону. Браузер запускається у видимому режимі, а стає нульовим — тобто «без таймауту». Ось звідки береться улюблена : під --debug тест по таймауту не падає, бо чекає скільки завгодно, а в CI на тому самому кроці валиться по штатному таймауту. Це не «локально стабільніше» — це інші налаштування.
npx playwright test --debug # Inspector: видимий браузер + таймаут 0
npx playwright test --ui # UI mode: time travel, watch-режим
Проклацувати кожну дію, щоб дійти до цікавого місця, не потрібно: page.pause() ставить усередині тесту, і після натискання «Resume» виконання зупиниться саме на ній.
await page.getByRole('button', { name: 'Checkout' }).click();
await page.pause(); // далі — руками в Inspector
Найцінніша частина Inspector — не покрокове виконання, а лог придатності. До моменту, коли інструмент став на паузу перед кліком, він уже виконав перевірки, і в лозі видно: чи локатор узагалі знайшов елемент, чи елемент видимий, увімкнений і стабільний, чи була прокрутка до нього. Якщо придатності досягти не вдалося, дія показується як pending — не як помилка. Це і є той розріз, який плутають найчастіше: «локатор не той» і «елемент ще не готовий» лікуються по-різному, а в звіті обидва спершу виглядають як таймаут. Самі критерії придатності — в главі про перевірки й автоочікування.
Поруч є ще два живі інструменти. Зі змінною PWDEBUG=console у DevTools зʼявляється обʼєкт playwright, тож прямо в паузі можна дивитися DOM і мережу браузера. А розширення для VS Code при падінні показує очікуване, отримане й повний call log просто в редакторі; у режимі Show Browser сесія браузера перевикористовується між прогонами.
post-mortem-режим — інший за природою. Trace viewer читає записаний (trace) уже після того, як скрипт відпрацював, і придуманий саме для падінь у CI, куди дебагером не залізеш.
UI mode: time travel і watch-режим
UI mode — окремий режим, а не косметика над --debug: він дає перегляд, запуск і розбір тестів із time travel та watch-режимом. Запускається npx playwright test --ui.
Що там реально корисно:
- Actions — для кожної дії видно, який локатор використано і скільки вона тривала.
- Повний лог того, що інструмент робить під капотом: прокрутка до елемента, очікування видимості, увімкненості й стабільності, потім сама дія. Той самий лог придатності, що в Inspector.
- Errors — повідомлення про помилки, а на таймлайні червона лінія на місці падіння.
- Консоль, у якій логи браузера й логи тестового файла позначені різними іконками. Дрібниця, яка економить хвилини: одразу видно, чиє це повідомлення — застосунку чи твого
console.log. - Playground для локаторів — правиш локатор і бачиш, чи він щось знаходить у DOM-знімку.
- Watch-режим — клік по іконці, і тест перезапускається на кожну зміну.
Практична різниця з ручним записом трейсу названа в доці прямо: у режимі розробки трейс вмикають прапорцем --trace on, а UI mode трейсить кожен тест сам. Тобто окремо його вмикати не треба.
І одне обмеження, яке варто знати до першого зіткнення: UI mode не враховує setup-тести, їх доводиться запускати вручну. Якщо проєкт логіниться setup-проєктом і кладе стан у файл — саме тут виникає «в UI падає, а в звичайному рані ні». Механіка setup-проєктів — у главах про фікстури й конфігурацію та автентифікацію й повторне використання стану.
Що лежить у трейсі
Трейс — це запис ходу виконання тесту, а не . Різниця принципова, тому варто перелічити, що всередині:
- Дії — використаний локатор і тривалість кожної дії, з переходом уперед і назад у часі.
- DOM-знімки для кожної дії: наводиш на дію — бачиш, як змінилася сторінка.
- Помилки з таймлайном, де падіння позначене червоною лінією, і вкладка з вихідним кодом, яка показує сам рядок.
- Мережа — усі запити прогону, з сортуванням за типом запиту, , методом, типом вмісту, тривалістю й розміром. Це той самий матеріал, з яким працює глава про перехоплення й мокання мережі, тільки постфактум.
- Консоль — повідомлення браузера й тесту.
- Метадані — браузер, розмір вікна, тривалість тесту.
- Вкладення — зокрема діф зображень разом із фактичним і очікуваним скріншотами, якщо в прогоні були візуальні порівняння.
Ще одна властивість, важлива для закритих середовищ: трейс завантажується повністю в браузері й нічого не передає назовні. Це самодостатній файл, який можна прикріпити до тікета: щоб його прочитати, дані нікуди вивантажувати не треба.
Чому цього не заміняє скріншот падіння? Бо скріншот — один кадр стану, а причина зазвичай у послідовності: який локатор спрацював, скільки він чекав, що прийшло з мережі перед тим. Канон автоматизації дивиться на це так само: скріншоти й записи екрана — легітимне джерело даних, і зберігають їх саме для аналізу першопричини, поруч із логами SUT, логами фреймворку як аудиторським слідом і логами . У разі падіння рішення автоматизації має зберегти все, що потрібне для аналізу.
Стратегії запису: чому не «трейс завжди»
Спокуса очевидна: вмикаємо трейс на кожен тест — і будь-яке падіння вже розібране. Дока цього не рекомендує прямо: писати трейс на всі тести дуже дорого за продуктивністю — платиш часом прогону, а зазвичай і місцем під артефакти.
Тому канонічна розкладка така:
| Де | Стратегія | Що отримуєш |
|---|---|---|
| Локальна розробка | --trace on або UI mode | Трейс кожного прогону — вартість тут зазвичай не критична |
| CI | trace: 'on-first-retry' | trace.zip для кожного тесту, який ретраївся |
| CI, «щоб було» | trace: 'on' | Повний запис — і сповільнений прогін; дока радить так не робити |
Стратегія on-first-retry — не компроміс, а точне попадання: трейс потрібен рівно там, де тест уже впав, тож його пишуть на першому ретраї (retry) невдалого тесту. Наслідок, на який натикаються всі: якщо ретраїв у конфігурації немає, трейсів теж не буде — записувати нічого, бо ретраїв не сталося.
Ретрай тут працює як прилад, а не як замазка: розводить три стани, а не два. passed — пройшов з першого разу; flaky — упав, але пройшов на повторі; failed — упав і на першому прогоні, і на всіх ретраях. Тест навіть бачить, що він на ретраї (testInfo.retry). Політика ретраїв — тема розділу «Автоматизація тестування», механіка засобами інструмента — глава про боротьбу з флаком.
Конфігурація має рівні, які легко переплутати: опції самого ранера живуть на верхньому рівні, опції оточення тесту — в секції use. Штатний приклад із доки навмисно різнить локальний і CI-режим:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
forbidOnly: !!process.env.CI, // забутий test.only валить білд у CI
retries: process.env.CI ? 2 : 0, // ретраї лише в CI
use: {
trace: 'on-first-retry', // трейс лише на повторі впалого тесту
},
});
Скріншоти й відео при падінні
Для CI-падінь дока Playwright формулює вибір однозначно: використовуй trace viewer замість відео й скріншотів, бо трейс дає повний слід — таймлайн, DOM-знімки кожної дії з через DevTools, мережеві запити. Скріншот і відео відповідають на питання «що було видно», трейс — на питання «що відбувалося».
Це не означає «скріншоти не потрібні». Вони лишаються там, де симптом треба показати людині, яка трейс не відкриє, і там, де зображення — це сам предмет перевірки: у візуальному тестуванні еталон, фактичний знімок і діф читають саме як вкладення трейсу. Аргумент вартості діє й тут: артефакти збирають на падінні або ретраї, а не на кожному зеленому прогоні.
Репортери: людині, машині і CI
Перше, що варто засвоїти: репортери (reporters) не взаємовиключні. Їх вмикають кілька одночасно — наприклад, читабельний вивід у термінал і машинний файл із результатами. І локальний набір свідомо відрізняється від CI-набору: локально дефолт — list (рядок на кожен тест), у CI — dot (один символ на успішний тест), щоб не заливати лог.
| Репортер | Що дає |
|---|---|
list | Рядок на кожен тест; дефолт локально |
line | Один рядок про останній завершений тест плюс падіння в міру появи; для великих сюїт |
dot | Один символ на кожен успішний тест; дефолт у CI |
html | Самодостатня тека зі звітом, яку можна віддати як вебсторінку |
json | Обʼєкт з усією інформацією про прогін |
junit | XML у стилі JUnit — формат обміну для CI-систем, а не звіт для людини |
blob | Усі деталі прогону; головне призначення — злиття звітів шардів |
reporter: process.env.CI
? [['dot'], ['html'], ['junit']] // людині, для перегляду, для CI
: [['list']],
blob варто розуміти окремо: це проміжний формат, з якого потім роблять будь-який інший звіт. Файли шардів кладуть в одну теку й зливають, а конфліктів імен немає, бо номер шарда входить у назву файла (report-<hash>-<shard_number>.zip). Детальніше про (sharding) — у главі про паралельний запуск.
Allure — оглядово (ширше про звітність і тренди — у розділі «Автоматизація тестування»). Дві речі, які тут плутають постійно:
- Історія й ретраї — різне. Ретраї — це повтори всередині одного прогону; історія — звʼязок між різними звітами. Механізм звʼязування — унікальний ідентифікатор тесту, тому перейменування тесту рве історію, і тренд починається з нуля.
- Історія не зʼявляється сама. В Allure 2 теку
historyз попереднього звіту треба скопіювати в теку результатів перед генерацією нового — інакше кожен звіт буде першим у житті.
Корисні й категорії: інструмент розводить Product errors (тест failed) і Test errors (тест broken), кожен результат належить рівно одній категорії, а кастомні правила матчаться першими й у порядку оголошення. Це той самий поділ «баг продукту чи баг тесту», тільки автоматизований у звіті.
І рамка, яку варто тримати над усім інструментарієм. Логи звітом не є: вони дають деталі кроків, але не дають огляду результатів прогону. Звіт про прогрес (test progress report) за каноном must містити результати, інформацію про систему під тестом і опис оточення — у формі, придатній для конкретної аудиторії, і should публікуватися всім релевантним стейкхолдерам. Деталізація законно різниться залежно від отримувача, а тренди вимагають аналізу попередніх прогонів.
Розбір фейлу в CI: від репорту до першопричини
Головний факт, з якого випливає вся дисципліна артефактів: на ранерах GitHub кожен прогін іде на свіжій, щойно розгорнутій віртуальній машині, а кожна — у власному ранері або . Дані вільно ходять лише між кроками однієї джоби, бо вони на тому самому ранері. Практичний висновок жорсткий: якщо трейс не вивантажено артефактом, його немає. «Зайду на агент подивлюся» не існує як план.
Далі — порядок, який перетворює червоний звіт у причину:
Кілька кроків варті окремого слова.
Статус — це вже половина діагнозу. flaky означає, що тест упав і пройшов на повторі: продукт, найімовірніше, живий, а проблема — у детермінованості тесту або даних. І трейс у тебе якраз є, бо on-first-retry записав саме цей повтор.
Історія важливіша за один прогін. Канон радить тримати історію звітів, щоб збирати статистику про тести й з частими — це і є матеріал для трендів, і це ж спосіб відповісти на перше питання : чи таке падіння вже траплялося.
Два вердикти, які легко переплутати. Якщо фактичний і очікуваний результати збігаються, а тест червоний — найімовірніше дефект у самому рішенні автоматизації, а не в продукті. А якщо впали всі тести, канон велить першою підозрою ставити недоступне оточення, а не масову регресію: перед тим як заводити тридцять багів, перевір, чи стенд узагалі піднявся. Зшити тестовий лог із логами системи допомагає кореляційний ідентифікатор (correlation ID, trace ID) — один наскрізний id на запит.
Коли локально не відтворюється — перше питання не «який локатор», а чи падає тест, коли він єдиний у прогоні. Це найшвидший спосіб відділити взаємодію тестів між собою від справжнього дефекту; у каталозі нестабільних тестів цей клас так і називається — тести, що взаємодіють (Interacting Tests).
Окремий клас — «тести не запустилися взагалі». Якщо в CI падає не , а старт браузера, розбирати трейс нічого: змінна DEBUG=pw:browser виводить логи запуску браузера, і дока радить її саме на помилках «Failed to launch browser». За замовчуванням браузери стартують headless, а видимий режим на Linux-агенті вимагає встановленого Xvfb (в офіційному Docker- й GitHub Action він уже є).
Типові помилки
- «Локально проходить, у CI падає по таймауту» — виглядає як капризи інфраструктури, а насправді ти ганяв тест під
--debug, де таймаут дорівнює нулю. Локально він не падав не тому, що швидший, а тому, що йому дозволили чекати вічно. - «У UI mode тест червоний, у звичайному рані зелений» — виглядає як баг режиму, а насправді UI mode не враховує setup-тести: setup-проєкт, який логінить і кладе стан, треба запустити вручну.
- «Увімкнули
on-first-retry, а трейсів у CI немає» — виглядає як зламаний конфіг, а насправді трейс пишеться на ретраї: якщо ретраї не ввімкнені, записувати нічого. - «Є скріншот падіння — розберемось» — виглядає як діагностика, а насправді один кадр не каже, який локатор спрацював, скільки він чекав і що прийшло з мережі. Для аналізу першопричини потрібен слід, а не лише картинка.
- «Артефакт не вивантажили, зайду на агент подивлюся» — виглядає як план, а насправді на ранерах GitHub прогін ішов на свіжій віртуальній машині, якої вже не існує.
- «Перейменували тест — і тренд у звіті обнулився» — виглядає як баг звіту, а насправді історія звʼязує прогони за унікальним ідентифікатором тесту, і нова назва — це для звіту новий тест.
- «Шардували прогін — отримали пʼять звітів замість одного» — виглядає як поломка, а насправді єдиний звіт — це окремий крок злиття blob-звітів, а не побічний ефект шардінгу.
- «Тест червоний — значить, баг у продукті» — виглядає як логіка, а насправді якщо фактичний і очікуваний результати збігаються, дефект найімовірніше в самому рішенні автоматизації; а якщо впало все — питання передусім до оточення, не до продукту.
Підсумок
- Прапорець
--debugміняє конфігурацію, а не лише відкриває вікно: видимий браузер і нульовий таймаут. Значна частина розходжень «локально/CI» — саме тут. - Живий і
post-mortem-розбір розвʼязують різні задачі. Inspector і UI mode працюють там, де падіння відтворюється; трейс — єдиний спосіб розібрати те, що падає лише в CI, і читається без відтворення. - Трейс — це слід, а не кадр: дії з локаторами й тривалістю, DOM-знімки, мережа, консоль, метадані оточення. Тому дока радить його замість відео й скріншотів для CI-падінь — і не радить вмикати на кожен тест.
- Артефакт існує лише тоді, коли його вивантажено: прогін живе на свіжій віртуальній машині, а шардований прогін дає один звіт лише після злиття blob-звітів.
- Звіт — не лог і не «у нас Allure». Канон вимагає результатів, даних про систему й оточення в придатній для аудиторії формі, а тренди — історії прогонів, звʼязаної за ідентифікаторами тестів.
Можливі питання
- «Тест падає в CI, локально проходить — що робиш?» — очікують не «перезапущу», а метод: трейс на ретраї, артефакт, дія й локатор, мережа й метадані оточення. Інтервʼюер дивиться, чи є в тебе процедура, а не інтуїція.
- «Що таке trace viewer і що в трейсі є?» — сильна відповідь називає склад (дії з локаторами й часом, DOM-знімки, мережу, консоль, метадані, вкладення) і головну властивість: це розбір після факту, без відтворення.
- «Чому не писати трейс завжди?» — чекають аргумент вартості й знання штатної стратегії
on-first-retry; додатковий плюс — наслідок «без ретраїв трейсу не буде». - «Чим UI mode відрізняється від debug mode?» — розводять живий покроковий розбір з логом придатності і режим із
time travel, watch-режимом та автоматичним трейсуванням; згадка про пастку зі setup-тестами показує реальний досвід. - «Які репортери використовуєш і навіщо кілька?» — перевіряють, чи розумієш різні аудиторії: людський вивід у термінал, HTML для перегляду, JUnit XML як формат обміну для CI, blob для злиття шардів.
- «Як зрозуміти, це баг продукту чи баг тесту?» — сильна відповідь дає ознаки: збіг фактичного й очікуваного при червоному тесті вказує на дефект автоматизації, масове падіння — на оточення, а
flaky— на недетермінованість тесту або даних. Додатковий плюс — згадка трейсу й кореляційного ID як доказів у баг-репорті.
Джерела
Два режими: наживо і після факту
- Playwright — Debugging Tests —
--debugяк зміна конфігурації (видимий браузер, нульовий таймаут),page.pause(), склад логів придатності,PWDEBUG=console, поведінка розширення VS Code. - Playwright — Trace viewer — трейс як
post-mortem-розбір «after the script has run», призначений для падінь у CI. - Playwright — Auto-waiting (actionability) — перелік перевірок придатності, які інспектор виводить у лог.
UI mode: time travel і watch-режим
- Playwright — UI Mode —
time travelі watch-режим, склад вкладок, розділення логів браузера й тесту, обмеження щодо setup-тестів. - Playwright — Trace viewer —
--trace onу режимі розробки й автоматичне трейсування кожного тесту в UI mode.
- Playwright — Trace viewer — склад трейсу: дії з локаторами й тривалістю, DOM-знімки, помилки й таймлайн, мережа, метадані, вкладення з дифами; трейс не передає даних назовні.
- Playwright — Debugging Tests — трейс як DOM-знімок кожної дії плюс час, параметри, значення, лог, консоль, мережа й вихідний код.
- ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §4.2, §6.1.1: перелік джерел даних для аналізу, скріншоти для аналізу першопричини, вимога зберігати при падінні все потрібне для аналізу.
Стратегії запису: чому не «трейс завжди»
- Playwright — Best Practices — для CI-падінь trace viewer замість відео й скріншотів;
trace: 'on'на кожен тест не рекомендований через вартість. - Playwright — Trace viewer —
--trace onу розробці,on-first-retryу CI іtrace.zipна кожен ретраєний тест. - Playwright — Test configuration — опції ранера на верхньому рівні проти секції
use; штатний приклад із ретраями лише в CI і трейсом на ретраї. - Playwright — Test retries — три стани результату (
passed,flaky,failed) іtestInfo.retry. - ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1: при статусі
failedпотрібна додаткова інформація про причину, зокрема скріншоти.
Репортери: людині, машині і CI
- Playwright — Reporters — кілька репортерів одночасно, різні набори локально й у CI, призначення
list/line/dot/html/json/junit/blob, JUnit XML як формат обміну. - Playwright — Sharding — злиття blob-звітів в одній теці й номер шарда в імені файла.
- Allure Report — History and retries — історія проти ретраїв, звʼязування прогонів за унікальним ідентифікатором тесту, копіювання теки
historyв теку результатів у Allure 2. - Allure Report — Categories —
Product errorsпротиTest errors, одна категорія на результат, порядок кастомних правил. - ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1, §6.1.3: логи не дають огляду, обовʼязковий склад звіту про прогрес, публікація стейкхолдерам, залежність деталізації від аудиторії, тренди з попередніх прогонів.
Розбір фейлу в CI: від репорту до першопричини
- GitHub Docs — Understanding GitHub Actions — свіжа щойно розгорнута віртуальна машина на кожен прогін, власний ранер чи контейнер на кожну джобу, обмін даними між кроками однієї джоби.
- Playwright — Trace viewer — трейс як інструмент розбору падінь CI: дії з локаторами, помилки з таймлайном, мережа, метадані оточення.
- Playwright — Test retries —
flakyяк окремий стан «упав, але пройшов на ретраї». - Playwright — Continuous Integration —
DEBUG=pw:browserдля помилок запуску браузера, headless за замовчуванням, Xvfb для видимого режиму на Linux-агентах. - ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1–6.1.3: процедура розбору падіння, збіг фактичного й очікуваного як ознака дефекту рішення автоматизації, масове падіння як симптом недоступного оточення, кореляційний ID, історія звітів для трендів.
- Jest — Setup and Teardown — порада перевіряти передусім, чи падає тест, коли він єдиний у прогоні.
- xUnit Test Patterns — Erratic Test — той самий клас нестабільності: тести, що взаємодіють між собою.
- Playwright — Debugging Tests — нульовий таймаут під
--debugяк причина розходження локального прогону й CI. - Playwright — UI Mode — UI mode не враховує setup-тести, їх запускають вручну.
- Playwright — Trace viewer — трейс пишеться на першому ретраї впалого тесту, по одному
trace.zipна ретраєний тест. - Playwright — Sharding — окремі звіти шардів зливають в один окремим кроком.
- Allure Report — History and retries — звʼязування прогонів за унікальним ідентифікатором тесту.
- GitHub Docs — Understanding GitHub Actions — свіжа віртуальна машина на кожен прогін.
- ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1–6.1.2: скріншоти як частина даних для аналізу першопричини, збіг фактичного й очікуваного, масове падіння як симптом оточення.
- Playwright — Debugging Tests —
--debugяк зміна конфігурації: видимий браузер і нульовий таймаут. - Playwright — Trace viewer — трейс як
post-mortem-розбір і його склад: дії з локаторами й тривалістю, DOM-знімки, мережа, консоль, метадані. - Playwright — UI Mode — живий розбір із
time travelі watch-режимом. - Playwright — Best Practices — трейс замість відео й скріншотів для CI-падінь і вартість
trace: 'on'. - Playwright — Sharding — окремі звіти шардів і злиття blob-звітів в один.
- GitHub Docs — Understanding GitHub Actions — свіжа щойно розгорнута віртуальна машина на кожен прогін.
- Allure Report — History and retries — звʼязування прогонів за унікальним ідентифікатором тесту.
- ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1, §6.1.3: логи не дають огляду, обовʼязковий склад звіту про прогрес, тренди з попередніх прогонів.
- Playwright — Trace viewer — склад трейсу,
post-mortem-розбір, стратегія запису на першому ретраї. - Playwright — UI Mode — відмінності UI mode:
time travel, watch-режим, обмеження щодо setup-тестів. - Playwright — Reporters — призначення репортерів і одночасне використання кількох.
- Playwright — Best Practices — трейс замість відео й скріншотів для CI-падінь і вартість
trace: 'on'. - ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §6.1.1–6.1.3: ознаки дефекту рішення автоматизації, масове падіння як симптом оточення, кореляційний ID, вимоги до звіту.
Відео до теми
Що робить прапорець --debug і чому під ним тест «раптом перестає падати»?
Він не просто відкриває вікно з браузером — він переписує параметри прогону. Браузер стартує видимим, а тесту стає нульовим, тобто очікування перестають обмежуватись у часі. Звідси й ефект: крок, який у валиться по таймауту, під --debug спокійно дочекається елемента й дасть зелений результат. Кандидат, який цього не знає, робить хибний висновок «локально все добре, винна інфраструктура», хоча порівнював дві різні конфігурації. Практичне правило: відтворювати CI-падіння треба зі штатними таймаутами, а --debug брати для розгляду кроку зблизька, а не як доказ стабільності.
Навіщо page.pause(), якщо Inspector і так виконує тест покроково?
Щоб не клацати «далі» двадцять разів до потрібного місця. Виклик ставить просто в коді тесту: після натискання «Resume» прогін біжить у звичайному темпі й гальмує рівно там, де ти його попросив. Далі відкривається все те саме — поточний стан сторінки, підбір , лог придатності до дії (actionability). Найчастіший сценарій використання — довгий сценарій із логіном і кількома переходами, де цікавий лише передостанній крок. Рядок із паузою в комітований код, звісно, не їде: це інструмент розслідування, а не частина тесту.
Що таке лог придатності (actionability log) і чому це найцінніше в Inspector?
Перед кожною дією інструмент проганяє серію перевірок готовності елемента, і саме їхній результат видно в лозі: чи локатор узагалі когось знайшов, чи елемент видно, чи він увімкнений, чи перестав рухатися, чи була прокрутка до нього. Це відповідь на питання «на чому саме воно застрягло», якої немає в короткому повідомленні про таймаут. Тому лог розводить два діагнози, що ззовні виглядають однаково: локатор не той (нічого не знайдено взагалі) і елемент ще не готовий (знайдено, але, скажімо, перекрито оверлеєм). Лікуються вони по-різному: у першому випадку правиться селектор, у другому — очікування правильного стану або . Той самий лог доступний і в UI mode, і в , тож звичку його читати варто виробити один раз.
Дію в Inspector позначено як pending — це помилка?
Ні, це стан «умови для дії ще не виконані». Інструмент не червонить крок одразу: він продовжує перевіряти готовність елемента, поки дія не стане можливою або поки не вичерпається таймаут — а під --debug той нульовий, тож чекати можна скільки завгодно. Тобто pending — це вікно, у якому ще можна побачити причину, а не вердикт. Якщо в цей момент подивитися лог придатності, зазвичай видно конкретний пункт, який не проходить, — елемент невидимий, вимкнений або постійно рухається через анімацію. А ось у звіті все це вже злипнеться в один рядок про таймаут, з якого причини не витягнеш. Саме тому розбір «наживо» дешевший, коли падіння відтворюється локально.
Чим UI mode відрізняється від режиму --debug?
Це різні жанри. --debug — покрокове виконання одного тесту з видимим браузером і знятим таймаутом: ти сидиш поруч і керуєш. UI mode — оболонка над усією : список тестів, запуск вибіркою, watch-режим із перезапуском на кожну зміну файла і time travel по вже виконаному прогону. Ще одна практична різниця: у режимі розробки трейс вмикають окремим прапорцем, а UI mode пише його самостійно для кожного тесту, тож нічого налаштовувати не треба. Плюс там є playground для локаторів, окремі вкладки з діями, помилками, — і в консолі логи браузера відрізняються від логів тестового файла іконкою, що економить час на питанні «чиє це повідомлення».
У UI mode тест червоний, а у звичайному прогоні зелений. Що перевірити першим?
Чи не залежить тест від setup-проєкту. UI mode не тягне setup-тести автоматично — їх треба запускати руками, і якщо логін виконується саме setup-проєктом, який кладе стан автентифікації у файл, то в UI mode цього стану просто немає. Симптом виглядає як баг режиму, а насправді це різниця у складі прогону. Перевіряється швидко: запустити setup-проєкт окремо, а потім повторити тест. Якщо позеленів — питання закрите; якщо ні, шукаємо далі, але вже без хибної гіпотези про «зламаний UI mode».
Що таке trace viewer і чим він принципово відрізняється від Inspector та UI mode?
Це post-mortem-розбір: інструмент читає запис прогону, який уже завершився, і не потребує ані запущеного браузера, ані відтворення сценарію. Живі засоби корисні, поки збій повторюється на твоїй машині; трейс (trace) закриває протилежний випадок — коли падіння існує лише в пайплайні й живе рівно стільки, скільки лежить артефакт. Читається трейс без доступу до агента: це самодостатній файл, який відкривають локально й прикріплюють до тікета. Ще одна властивість, критична для закритих контурів: розбір відбувається повністю в браузері, назовні дані не йдуть, тож вивантажувати логи прогону в чужий сервіс не доводиться.
Що лежить усередині трейсу?
Трейс — це слід виконання, а не кадр. Усередині: перелік дій із локатором і тривалістю кожної, DOM-знімки на кожну дію (наводиш — бачиш, якою була сторінка саме тоді), помилки з таймлайном, де момент падіння підсвічено, плюс окрема вкладка з кодом тесту, підведеним до потрібного рядка. Далі мережа — усі запити прогону з методом, статусом, типом вмісту, тривалістю й розміром; консоль із повідомленнями браузера й тесту; метадані оточення — браузер, розмір вікна, тривалість тесту. Окремо — вкладення, серед яких для візуальних перевірок лежать еталон, фактичний знімок і діф. Сильна відповідь на співбесіді називає не лише склад, а й головний висновок: цього набору вистачає, щоб пройти шлях від симптому до дії й локатора без жодного відтворення.
Чому скріншот падіння не заміняє трейс?
Бо показує стан, а причина майже завжди у послідовності. З одного кадру не видно, який локатор спрацював, скільки він чекав, чи встиг доїхати запит, після якого мала зʼявитися кнопка. Тому для CI-падінь документація радить саме trace viewer замість відео й скріншотів: він відповідає на питання «що відбувалося», а картинка — лише на «що було видно». Це не означає, що скріншоти зайві. Вони потрібні у двох ситуаціях: коли симптом треба донести до людини, яка ніякий трейс відкривати не буде, і коли саме зображення перевіряють — у візуальних порівняннях еталон, поточний знімок і різниця між ними лежать вкладеннями всередині того ж запису.
Чому не вмикати запис трейсу на всі тести? Яка стратегія канонічна?
Бо це дорого: повний запис уповільнює прогін і роздуває артефакти, і документація прямо не радить так робити. Канонічна розкладка інша — локально під час розробки трейс пишуть на все (або просто працюють в UI mode, який трейсить сам), а в CI ставлять запис на першому (retry) впалого тесту. Логіка точна: трейс потрібен рівно там, де вже щось зламалося, і на кожен ретраєний тест отримуєш свій trace.zip. Тести, які пройшли з першого разу, не платять за це нічим — ні часом, ні місцем.
Увімкнули trace: 'on-first-retry', а трейсів у CI немає. Чому?
Тому що записувати нема на чому: ця стратегія прив'язана до ретраю, а ретраї в конфігурації вимкнені. Ззовні схоже на поламане налаштування, а насправді все відпрацювало за правилами: тест упав один раз, повтору не було, отже й моменту для запису не настало. Лікується або вмиканням ретраїв у CI, або зміною стратегії запису. Тут же корисно памʼятати, що опції й опції оточення тесту живуть на різних рівнях конфігурації: кількість ретраїв задають зверху, а трейс — у секції use, і плутанина цих рівнів дає ту саму симптоматику «налаштував, але не працює».
Які три стани результату розводить ранер і навіщо це на розборі?
passed — тест пройшов одразу; flaky — упав, але позеленів на повторі; failed — не пройшов ані з першого разу, ані на жодному ретраї. Це вже половина діагнозу до відкриття будь-якого артефакту. flaky майже завжди вказує на недетермінованість самого тесту чи даних, а не на зламаний продукт — і трейс за цей повтор у тебе якраз є, якщо стоїть запис на першому ретраї. failed без варіантів вимагає розбору, але й тут починають не з локатора, а з питання «чи червоний увесь прогін». Сам тест теж бачить, що виконується повторно — через testInfo.retry, і це дає змогу, наприклад, додатково логувати саме на повторі.
Навіщо вмикати кілька репортерів одночасно і чим вони різняться?
Тому що в результатів прогону різні . Репортери (reporters) не конкурують: у конфігурації їх перелічують списком і отримують кілька виводів з одного прогону. Людині в терміналі потрібен компактний прогрес — локально це list із рядком на кожен тест, у CI зазвичай dot, щоб не заливати лог тисячами рядків; для великих сюїт зручний line, який тримає один рядок про поточний тест і одразу показує падіння. Далі йдуть машинні формати: html — самодостатній звіт, який можна віддати як вебсторінку; json — повний обʼєкт із даними прогону; junit — XML, який розуміють CI-системи, тобто формат обміну, а не звіт для читання. Окремо стоїть blob, потрібний для злиття результатів. Сильна відповідь показує саме це розділення аудиторій, а не список назв.
Що таке blob-репортер і чому без нього шардований прогін дає пʼять звітів замість одного?
blob — проміжний формат із повними деталями прогону, з якого потім генерують будь-який інший звіт. При (sharding) кожен шард — окремий прогін (у CI зазвичай і окрема ), який нічого не знає про сусідів, тому кожен пише свій blob-файл. Далі всі ці файли складають в одну теку й зливають окремим кроком — і лише після цього виходить єдиний HTML-звіт по всьому прогону. Конфліктів імен не буває, бо номер шарда входить у назву файла. Головна пастка тут очікувано процесна: «отримали пʼять звітів» — це не поломка шардінгу, а просто пропущений крок злиття.
У звіті Allure після перейменування тесту обнулився тренд. Це баг звіту?
Ні. Історія звʼязує різні прогони між собою за унікальним ідентифікатором тесту, тож нова назва для звіту — це новий тест без минулого. Заодно варто розвести два поняття, які плутають постійно: ретраї — це повтори всередині одного прогону, а історія — це звʼязок між різними звітами. І друге, менш очевидне: сама собою історія не накопичується. В Allure 2 її тека переїжджає руками — вміст history з уже згенерованого звіту кладуть до результатів наступного прогону перед генерацією. Пропустив цей крок — і кожен звіт виходить без минулого, звідси й вічне «у нас тренди не працюють». Корисна поруч і система категорій: інструмент відділяє помилки продукту від помилок тесту, і кожен результат потрапляє рівно в одну категорію.
Чому план «зайду на агент і подивлюся трейс» не працює?
Бо агента вже немає. На ранерах GitHub під кожен прогін піднімається окрема свіжа віртуальна машина, а кожна джоба працює у власному ранері чи ; спільний доступ до файлів мають лише кроки в межах однієї джоби — вони на тому самому залізі. Щойно прогін завершився, машину прибрано разом з усім, що на ній лежало. Звідси жорсткий висновок: артефакт існує тільки тоді, коли його вивантажено окремим кроком. Тому крок з upload артефактів ставлять так, щоб він виконувався і на червоному прогоні, — інакше на розбір ти прийдеш рівно з тим текстом помилки, який був у лозі.
Тест падає в CI, локально проходить. Опиши свою процедуру.
Спершу статус, а не код: flaky і failed ведуть у різні гілки розбору. Далі — чи падало таке раніше: історія звітів відповідає на це швидше, ніж перечитування диффа, і одразу показує, чи це давній нестабільний тест. Потім трейс: на якій дії стало, який локатор використано, скільки він чекав, що каже лог придатності; поруч — мережа (чи не прилетів 500 або порожня відповідь) і метадані оточення, бо інший браузер чи менший розмір вікна пояснюють чимало «дивних» падінь. Якщо локально не відтворюється, наступне питання не про локатор, а про ізоляцію: запусти цей тест самого, без сусідів, і подивись, чи він взагалі червоний. Дешевшого способу відсіяти вплив інших тестів (Interacting Tests у класичному каталозі нестабільності) немає. І окремою гілкою — випадок «тести взагалі не стартували»: якщо валиться запуск браузера, розбирати в трейсі нічого.
Як за результатами прогону відрізнити баг продукту від бага тесту?
Через кілька ознак, кожна з яких перевіряється за артефактами. Червоний увесь прогін? Тоді першою гіпотезою беруть непідняте оточення, а не тридцять одночасних — спершу перевіряють, чи стенд узагалі відповідає, і лише потім заводять дефекти. Тест червоний, але отриманий результат дорівнює тому, на який розраховували? Це майже завжди поломка в самій автоматизації: кривий , гонка в очікуванні, застаріла тестова дата. Якщо статус flaky — питання до детермінованості тесту або даних, бо продукт на повторі відповів як треба. І навпаки: стабільне падіння одного сценарію з розбіжністю фактичного й очікуваного, підтверджене трейсом, — це вже матеріал у баг-репорт, куди йдуть крок, стан системи й самі артефакти. Щоб звʼязати тестовий лог із логами системи під тестом, використовують наскрізний кореляційний ідентифікатор (correlation ID) — один id на запит, за яким видно обидві сторони.
У CI не запускається браузер: тестів немає взагалі, трейсів теж. Що робиш?
Це окремий клас проблем, і трейс тут не допоможе — записувати нема чого, бо жодна дія не виконалася. Діагностика починається зі змінної DEBUG=pw:browser, яка вмикає логи запуску браузера: саме її документація радить на помилках виду «Failed to launch browser». Далі перевіряють базові речі оточення: за замовчуванням браузери стартують у headless-режимі, а видимий режим на Linux-агенті потребує встановленого Xvfb — в офіційному Docker- й у готовому GitHub Action він уже є, а на самописному образі його часто немає. Друга типова причина — не встановлені браузери або їхні системні залежності після зміни версії. Ознака, за якою цей клас упізнають одразу: червоне все й миттєво, а в лозі немає жодного асерту.
Три кейси про шлях від червоного прогону до причини: розбір впалого тесту в CI, конфігурація, яка взагалі дає артефакти для такого розбору, і таблиця , коли причина не одна. Скрізь — що дивитися і який висновок з цього робити.
Кейс 1. Трейс упалого тесту: читаємо слід замість здогадок
червона, у лозі один рядок про , локально сценарій проходить. Качаємо артефакт із , відкриваємо трейс і йдемо по вкладках у сталому порядку: дії → лог придатності → мережа → метадані.
Вкладка Actions показує, де саме стало і скільки воно там стояло:
✓ page.goto https://shop.example.com/cart 1.2 s
✓ getByRole('button', { name: 'Checkout' }).click() 340 ms
✗ expect(getByTestId('order-total')).toBeVisible() 5.0 s
Розгортаємо call log червоного кроку — той самий лог придатності до дії (actionability):
Expect "toBeVisible" with timeout 5000ms
- waiting for getByTestId('order-total')
9 × locator resolved to <span data-testid="order-total"></span>
- unexpected value "hidden"
Далі — вкладка Network того самого моменту:
Method URL Status Type Duration
POST /api/cart/checkout 502 xhr 1.4 s
GET /api/cart/summary 200 xhr 120 ms
Що дивитися і чому:
- знайшовся — значить, селектор ні до чого. У лозі написано
resolved to, тобто елемент у DOM є, але прихований. Якби локатор не знайшов нічого, рядок був би інший, і правити треба було б селектор. Це та сама розвилка «не той локатор» проти «елемент не готовий», яку короткий текст помилки склеює в один таймаут. 502наPOST /api/cart/checkout— і є причина. Сума замовлення не показалася не тому, що тест поспішив, а тому, що бекенд не створив замовлення. Тест повівся коректно: він чекав на стан, який не настав. У баг-репорт іде саме цей запит із відповіддю, а не скарга на нестабільний локатор.- DOM-знімок підтверджує версію очима. Наведення на впалу дію показує сторінку такою, якою вона була в момент падіння: блок із сумою в розмітці присутній, але порожній і прихований — рівно те, що описав лог.
- Метадані закривають гіпотезу «в мене інший браузер». Там видно браузер, розмір вікна й тривалість тесту. Чимало «дивних» падінь пояснюється меншим вікном на агенті, де елемент їде під фолд або ховається за бургер-меню.
- Якби той самий трейс показав
200на всіх запитах, а суму на місці — висновок був би протилежний: фактичний результат збігається з очікуваним, отже дефект найімовірніше в самому рішенні автоматизації (кривий , гонка в очікуванні, застаріла тестова дата).
Кейс 2. Конфігурація, після якої є що розбирати
Розбір із кейсу 1 можливий лише тому, що трейс записався й доїхав до артефактів. Ось мінімальний набір, який це забезпечує, з розділенням «локально» і «CI».
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
forbidOnly: !!process.env.CI, // забутий test.only не проскочить у пайплайн
retries: process.env.CI ? 2 : 0, // без ретраїв трейс на ретраї не запишеться
reporter: process.env.CI
? [['dot'], ['html'], ['junit', { outputFile: 'results.xml' }]]
: [['list']],
use: {
trace: 'on-first-retry', // запис лише там, де вже впало
},
});
І крок, без якого все попереднє марне: віртуальна машина прогону зникає разом із файлами, тож артефакти треба вивантажити — і саме на червоному прогоні.
- name: Upload Playwright artifacts
if: ${{ !cancelled() }} # без цього крок пропускається саме тоді, коли потрібен
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: |
playwright-report/
test-results/
Що дивитися і чому:
- Рівні конфігурації різні.
retries,reporterіforbidOnly— опції й живуть зверху, аtrace— опція оточення тесту в секціїuse. Класична причина «налаштував, а не працює» — трейс, покладений не на той рівень. on-first-retryбез ретраїв не запише нічого. Стратегія прив'язана до повтору впалого тесту: немає повтору — немає моменту для запису. Параretriesплюсtraceпрацює тільки разом.- Три репортери в CI — це три різні аудиторії.
dotтримає лог читабельним,htmlдає звіт, який відкриє людина,junit— XML для самої CI-системи, щоб та показала результати у своєму інтерфейсі. Локально доситьlistз рядком на кожен тест. - Умова
if: ${{ !cancelled() }}не косметика. Без неї крок вивантаження пропускається після падіння тестів — тобто рівно тоді, коли артефакт і потрібен; саме цю умову ставить на upload-крок штатний з доки Playwright. - Якщо прогін шардований, HTML-звіту одразу не буде. Кожен шард — окремий прогін (у CI зазвичай і окрема джоба), і кожен пише свій blob-файл; єдиний звіт зʼявляється після окремого кроку злиття, і «пʼять звітів замість одного» — це пропущений крок, а не поломка.
Кейс 3. Таблиця тріажу: симптом, перша гіпотеза, чим підтвердити
Червоний звіт сам по собі не каже, чий це баг. Порядок дій задає симптом, і майже кожну гіпотезу можна підтвердити або зняти за пару хвилин.
| Симптом у звіті | Перша гіпотеза | Чим підтвердити |
|---|---|---|
| Впали всі тести підряд | Оточення не піднялося | Ручний запит до стенда, статус деплою, лог першої джоби — до заведення дефектів |
| Тестів у звіті немає, лог порожній | Браузер не стартував | DEBUG=pw:browser у прогоні; перевірити headless-режим і наявність Xvfb на Linux-агенті |
Статус flaky | Недетермінованість тесту або даних | Трейс за ретрай: скільки чекав, які запити пішли, чи не той самий email на другому прогоні |
failed, локально зелено | Взаємодія тестів між собою | Запустити тест єдиним у прогоні; якщо зелено — питання до ізоляції стану, не до локатора |
| Фактичний збігається з очікуваним, тест червоний | Дефект у рішенні автоматизації | Асерт і очікування в трейсі; DOM-знімок на кроці падіння |
| Трейсів у артефактах немає | Ретраї вимкнені або крок upload пропущено | Конфіг (retries) і умова на кроці вивантаження |
| Тренд у звіті почався з нуля | Тест перейменували | Історія звʼязує прогони за ідентифікатором тесту; звірити назву з попереднім звітом |
Кілька приміток до таблиці:
- Статус читають до артефактів.
flakyіfailedведуть у різні гілки: перший — до детермінованості тесту, другий — до продукту або оточення. Це найдешевший фільтр з усіх наявних. - Історія важить більше за один прогін. Питання «чи падало таке раніше» відповідає швидше, ніж перечитування диффа: якщо тест червонів десять разів за місяць, це не наслідок сьогоднішнього релізу.
- Доказ у баг-репорті — артефакт, а не переказ. Трейс самодостатній і читається без відтворення, тож у тікет іде він, крок сценарію й стан системи. Щоб зшити тестовий лог із логами бекенду, зручний наскрізний кореляційний ідентифікатор (correlation ID) — один id на запит, за яким видно обидві сторони.
- лишається там, де він доречний. Показати симптом людині, яка трейс не відкриє, або порівняти еталон із фактичним знімком у візуальній перевірці — це його робота; шукати першопричину по одному кадру — ні.
Живий дебаг: Inspector і паузи
- Можу пояснити, що
--debugміняє конфігурацію прогону (видимий браузер плюс знятий ), і тому не роблю з «локально не падає» висновку про стабільність. - Знаю, навіщо
page.pause(), коли до цікавого кроку двадцять дій, і що цей рядок не їде в комітований код. - Читаю лог придатності до дії (actionability): знайдено чи ні, видимий, увімкнений, стабільний, прокручений у видиму область — і розрізняю за ним «локатор не той» та «елемент ще не готовий»; памʼятаю, що
pending— це невиконані умови, а не помилка. - Знаю про
PWDEBUG=console(обʼєктplaywrightу DevTools) і про режимShow Browserу розширенні для VS Code.
UI mode
- Можу назвати, чим UI mode відрізняється від
--debug: огляд усієї ,time travel, watch-режим і автоматичний кожного тесту без окремого прапорця. - Знаю обмеження зі setup-тестами й перевіряю його першим, коли в UI червоно, а у звичайному прогоні зелено.
Трейс і trace viewer
- Можу пояснити, що трейс (trace) читають після завершення прогону — без відтворення, без доступу до агента, повністю в браузері й без передавання даних назовні.
- Перелічу склад трейсу: дії з і тривалістю, DOM-знімки, помилки з таймлайном і рядком коду, мережа, консоль, метадані оточення, вкладення.
- Розумію, чому кадр не заміняє слід, і де усе ж доречний: показати симптом людині без трейсу і там, де зображення саме є предметом перевірки.
Стратегії запису артефактів
- Можу аргументувати, чому повний запис на кожен тест не рекомендують, знаю канонічну розкладку (усе підряд локально,
on-first-retryу CI) і наслідок: без увімкнених (retry) трейсів у не зʼявиться взагалі. - Не плутаю рівні конфігурації: опції зверху, опції оточення тесту — у секції
use. - Розрізняю статуси
passed,flakyіfailedта памʼятаю, що сам тест дізнається про свій повтор черезtestInfo.retry.
Репортери й звітність
- Розумію, що репортери (reporters) вмикаються набором, і можу назвати призначення
list,line,dot,html,json,junit,blobта їхніх . - Знаю, що
blob— проміжний формат, і що єдиний звіт при (sharding) зʼявляється лише після окремого кроку злиття. - Розводжу історію й ретраї, можу пояснити, чому перейменування тесту обнуляє тренд і що теку
historyв Allure 2 переносять руками. - Памʼятаю, що логи звітом не є: звіт має дати результати, дані про систему під тестом і оточення у формі, придатній для конкретної аудиторії.
Розбір падіння в CI
- Розумію, що прогін живе на щойно розгорнутій машині, тож невивантажений артефакт не існує.
- Починаю зі статусу й історії, а трейс відкриваю далі — і тримаю в голові дві підказки: отриманий результат дорівнює очікуваному при червоному тесті означає поломку в автоматизації, а червоний прогін цілком — непідняте оточення.
- Перевіряю тест поодинці, перш ніж шукати причину в локаторах, а в баг-репорт іду з артефактом і наскрізним кореляційним ідентифікатором (correlation ID), а не з переказом.
- Знаю, що робити, коли браузер узагалі не стартує: увімкнути
DEBUG=pw:browser, а далі перевірити режим запуску (типово headless) і наявність Xvfb, якщо агент на Linux має показувати вікно.
Квіз
Перед стартом
- Питань: 17
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Чому під `--debug` тест не падає по таймауту, а в CI на тому самому кроці валиться?

