← Python мануфактура

Після цього уроку ви зможете

Конспект і таймкоди

0:00

Принципи модуля й перевірка стартового стану

Модуль починається з чотирьох орієнтирів: KISS — тримати рішення простим; DRY — не дублювати знання; YAGNI — не будувати те, що ще не потрібне; DAMP — формулювати тест через описові й змістовні фрази. Вони не застосовуються механічно: спочатку потрібен робочий тест, а вже потім видно, що справді варто винести або перейменувати.

Перед новою роботою запускаються вже наявні тести. Це швидка перевірка, що вчорашні зміни або залежності не зламали базовий сценарій. Версії бібліотек у requirements.txt радять фіксувати, щоб оновлення залежності не змінило поведінку тестів безконтрольно.

3:00

Новий сценарій: логін і пошук проєкту

Створюється тест, який авторизується в застосунку й шукає проєкт «Python Manufacture». Спочатку кроки пишуться прямо в тесті: відкрити сторінку входу, заповнити email і пароль, натиснути Sign in, знайти поле пошуку.

Паралельно досліджується DOM: візуальна фільтрація не обов’язково видаляє непотрібні картки — застосунок може лише приховувати їх через CSS. Через це перевірка має враховувати не тільки наявність вузла в DOM, а й його видимість.

6:00

Семантичний локатор поля пошуку

Поле пошуку знаходиться через get_by_role("searchbox", name="Search"). Такий локатор спирається на доступну роль і назву елемента, тому краще відображає намір користувача, ніж випадковий CSS-клас.

Перед заповненням поля перевіряється to_be_visible(). Назва цільового проєкту зберігається у змінній, бо це одне й те саме предметне значення для введення та подальшого очікування.

Термін

Web-first assertion

Playwright expect(...) повторно перевіряє умову до успіху або завершення timeout, що прибирає потребу в ручних sleep для очікування UI-стану.

Приклад коду

Пошук проєкту через семантичні locators

from playwright.sync_api import Page, expect


def search_for_project(page: Page, target_project: str) -> None:
    search = page.get_by_role("searchbox", name="Search")
    expect(search).to_be_visible()
    search.fill(target_project)
    expect(page.get_by_role("heading", name=target_project)).to_be_visible()

Мінімальна helper-функція перевіряє видимість поля, заповнює його й очікує видимий heading з назвою проєкту.

Очікуваний результат: У target application поле Search заповнюється, а потрібний heading стає видимим.

Потрібно: playwright

9:00

Пошук проєкту й структура Python-тесту

Картку проєкту шукають як заголовок через get_by_role("heading", name=target_project). Відео порівнює це з CSS-пошуком на кшталт ul h3: семантичний варіант зазвичай чіткіше пояснює, що саме очікує тест.

Окремо показано, що блоки Python визначає відступ. Положення курсора й відступи впливають на те, чи IDE запускає одну тестову функцію, чи весь файл. Після двокрапки тіло функції має бути послідовно відформатоване.

13:00

Множинні збіги, `filter()` і `first()`

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()`

  1. Знайдіть у власному тесті locator, що повертає кілька елементів.
  2. Замініть позиційний вибір на роль і доступну назву або інший стабільний контракт.
  3. Додайте assertion саме на потрібний користувацький стан.

Результат: Тест однозначно знаходить елемент і падає, якщо контракт сторінки порушено.

18:00

Наявність тексту не дорівнює видимості

Експеримент показує, що to_have_text() може успішно знайти текст у прихованому DOM-елементі. Отже, така перевірка не доводить, що користувач бачить проєкт після фільтрації.

Для цього сценарію точніша перевірка — to_be_visible(). Висновок узагальнюється: assertion треба обирати за реальною вимогою. Якщо контракт про видимість — перевіряємо видимість; якщо про текстове значення незалежно від відображення — тоді to_have_text().

22:00

DRY: допоміжні функції без прихованих даних

Коли логін повторився у двох тестах, його винесено у login_user(page, email, password). Дані не хардкодяться всередині helper-функції: тест передає Page, email і пароль явно. Type hints допомагають IDE підказувати доступні операції та помічати неправильні аргументи ще до запуску.

Так само через Extract Method створюється open_home_page(page). Допоміжні функції розміщуються нижче тестів, щоб під час code review спочатку читалися сценарії, а вже потім технічні деталі.

27:00

DAMP і прискорення через прямий URL

Кроки отримують предметні назви, наприклад search_for_project(page, target_project). Завдяки цьому тіло тесту читається як послідовність дій, а низькорівневі локатори залишаються в helper-функціях.

Далі прибирається зайвий маршрут «головна сторінка → клік Login → сторінка входу». Якщо клік уже перевіряється окремим тестом, наступний сценарій може відкрити цільову сторінку входу напряму. У демонстрації це скорочує виконання приблизно з 6 до 4 секунд. Оптимізація коректна, доки перехід через головну сторінку не є предметом саме цього тесту.

33:00

Перемикання типу проєктів і негативна перевірка

Додається сценарій перемикання нативного select на Free Projects через select_option(). Після зміни категорії тест перевіряє, що попередній проєкт більше не видимий, а стан порожнього списку відображається.

Для очікувань можна задати явний timeout. Це верхня межа, а не обов’язкова пауза: assertion завершиться одразу після виконання умови. Локатор порожнього стану треба звузити до одного стабільного елемента; загальний текст може дати багато збігів і зламати strict mode.

39:00

Типізація, Arrange–Act–Assert і підсумок

Helper-функції типізуються, щоб зменшити ризик передати несумісне значення. Після рефакторингу набір містить сценарії невалідного логіну, успішної авторизації з пошуком і перемикання категорії проєктів.

Наприкінці вводиться структура Arrange–Act–Assert: підготувати дані й передумови, виконати дію, перевірити результат. Arrange може згодом переїхати у fixture, але на цьому етапі важливіше явно бачити три ролі коду. Практика після відео — додати кілька сценаріїв і виносити helper-функції лише там, де вони справді покращують читання або прибирають повторення.

Термін

Arrange–Act–Assert

Pytest описує тест як послідовність підготовки стану, однієї цільової дії, перевірки результату та, за потреби, cleanup.

Джерела та додаткові матеріали

  • Locators ↗Microsoft Playwright · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: Locating elements / Strictness.

  • Assertions ↗Microsoft Playwright · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: Auto-retrying assertions.

  • Anatomy of a test ↗pytest · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: Arrange, Act, Assert, Cleanup.