1. Рефакторинг та оптимізація, KISS, DRY, DAMP, YAGNI
На прикладі Playwright-тестів автор показує, як почати з простого робочого сценарію, а потім прибрати підтверджене дублювання, дати діям предметні назви й скоротити зайві UI-переходи. Головна теза: тест спершу має приносити цінність, а рефакторинг — робити його читабельнішим і швидшим, не створюючи структуру «про запас».
Примітка: конспект укладено за автоматичними українськими субтитрами; назви API та технічні терміни нормалізовано за контекстом відео.
Після цього уроку ви зможете
Пояснювати роль KISS, DRY, DAMP і YAGNI під час еволюції UI-тесту.
Обирати семантичний Playwright locator і assertion відповідно до спостережуваної вимоги.
Виносити повторювані дії у helper-функції без прихованих test data.
Скорочувати зайві UI-переходи, не втрачаючи предмет перевірки.
Модуль починається з чотирьох орієнтирів: KISS — тримати рішення простим; DRY — не дублювати знання; YAGNI — не будувати те, що ще не потрібне; DAMP — формулювати тест через описові й змістовні фрази. Вони не застосовуються механічно: спочатку потрібен робочий тест, а вже потім видно, що справді варто винести або перейменувати.
Перед новою роботою запускаються вже наявні тести. Це швидка перевірка, що вчорашні зміни або залежності не зламали базовий сценарій. Версії бібліотек у requirements.txt радять фіксувати, щоб оновлення залежності не змінило поведінку тестів безконтрольно.
Створюється тест, який авторизується в застосунку й шукає проєкт «Python Manufacture». Спочатку кроки пишуться прямо в тесті: відкрити сторінку входу, заповнити email і пароль, натиснути Sign in, знайти поле пошуку.
Паралельно досліджується DOM: візуальна фільтрація не обов’язково видаляє непотрібні картки — застосунок може лише приховувати їх через CSS. Через це перевірка має враховувати не тільки наявність вузла в DOM, а й його видимість.
Поле пошуку знаходиться через get_by_role("searchbox", name="Search"). Такий локатор спирається на доступну роль і назву елемента, тому краще відображає намір користувача, ніж випадковий CSS-клас.
Перед заповненням поля перевіряється to_be_visible(). Назва цільового проєкту зберігається у змінній, бо це одне й те саме предметне значення для введення та подальшого очікування.
Термін
Web-first assertion
Playwright expect(...) повторно перевіряє умову до успіху або завершення timeout, що прибирає потребу в ручних sleep для очікування UI-стану.
Картку проєкту шукають як заголовок через get_by_role("heading", name=target_project). Відео порівнює це з CSS-пошуком на кшталт ul h3: семантичний варіант зазвичай чіткіше пояснює, що саме очікує тест.
Окремо показано, що блоки Python визначає відступ. Положення курсора й відступи впливають на те, чи IDE запускає одну тестову функцію, чи весь файл. Після двокрапки тіло функції має бути послідовно відформатоване.
Playwright у strict mode очікує один елемент для дії або перевірки. Загальний локатор h3 повертає багато заголовків, тому тест падає. first() технічно усуває множинність, але не гарантує, що обрано саме потрібний проєкт: перший елемент може виявитися зовсім іншим.
Надійніший підхід — звузити локатор за змістом, наприклад через роль і name або через filter(has_text=target_project). first() доречний лише тоді, коли порядок є частиною контракту, а не способом приховати нечіткий селектор.
Уточнення
Не лікуйте нечіткий locator через `first()`
Playwright радить використовувати first() і last() обережно: після зміни сторінки вони можуть вибрати інший елемент. Краще сформувати унікальний locator за роллю, назвою або іншим стабільним контрактом.
Термін
Locator strictness
Playwright виконує strictness-перевірку для операцій над одним цільовим елементом: множинний збіг спричиняє помилку, тому locator треба звузити за контрактом інтерфейсу.
Практика
Звузити locator без `first()`
Знайдіть у власному тесті locator, що повертає кілька елементів.
Замініть позиційний вибір на роль і доступну назву або інший стабільний контракт.
Додайте assertion саме на потрібний користувацький стан.
Результат: Тест однозначно знаходить елемент і падає, якщо контракт сторінки порушено.
Експеримент показує, що to_have_text() може успішно знайти текст у прихованому DOM-елементі. Отже, така перевірка не доводить, що користувач бачить проєкт після фільтрації.
Для цього сценарію точніша перевірка — to_be_visible(). Висновок узагальнюється: assertion треба обирати за реальною вимогою. Якщо контракт про видимість — перевіряємо видимість; якщо про текстове значення незалежно від відображення — тоді to_have_text().
Коли логін повторився у двох тестах, його винесено у login_user(page, email, password). Дані не хардкодяться всередині helper-функції: тест передає Page, email і пароль явно. Type hints допомагають IDE підказувати доступні операції та помічати неправильні аргументи ще до запуску.
Так само через Extract Method створюється open_home_page(page). Допоміжні функції розміщуються нижче тестів, щоб під час code review спочатку читалися сценарії, а вже потім технічні деталі.
Кроки отримують предметні назви, наприклад search_for_project(page, target_project). Завдяки цьому тіло тесту читається як послідовність дій, а низькорівневі локатори залишаються в helper-функціях.
Далі прибирається зайвий маршрут «головна сторінка → клік Login → сторінка входу». Якщо клік уже перевіряється окремим тестом, наступний сценарій може відкрити цільову сторінку входу напряму. У демонстрації це скорочує виконання приблизно з 6 до 4 секунд. Оптимізація коректна, доки перехід через головну сторінку не є предметом саме цього тесту.
Додається сценарій перемикання нативного select на Free Projects через select_option(). Після зміни категорії тест перевіряє, що попередній проєкт більше не видимий, а стан порожнього списку відображається.
Для очікувань можна задати явний timeout. Це верхня межа, а не обов’язкова пауза: assertion завершиться одразу після виконання умови. Локатор порожнього стану треба звузити до одного стабільного елемента; загальний текст може дати багато збігів і зламати strict mode.
Helper-функції типізуються, щоб зменшити ризик передати несумісне значення. Після рефакторингу набір містить сценарії невалідного логіну, успішної авторизації з пошуком і перемикання категорії проєктів.
Наприкінці вводиться структура Arrange–Act–Assert: підготувати дані й передумови, виконати дію, перевірити результат. Arrange може згодом переїхати у fixture, але на цьому етапі важливіше явно бачити три ролі коду. Практика після відео — додати кілька сценаріїв і виносити helper-функції лише там, де вони справді покращують читання або прибирають повторення.
Термін
Arrange–Act–Assert
Pytest описує тест як послідовність підготовки стану, однієї цільової дії, перевірки результату та, за потреби, cleanup.