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

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

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

0:00

Selenium як набір інструментів і залежність проєкту

Selenium розглядається не як одна функція для керування браузером, а як екосистема. Для Python-тестів ключовим є Selenium WebDriver; Selenium IDE дає змогу записати простий сценарій у браузері й згенерувати початковий код, а Grid стосується розподіленого запуску.

Залежність додається через pip install selenium або uv add selenium, після чого середовище треба синхронізувати. Допоміжний pytest-selenium може спростити старт, але урок застерігає від прив’язки до слабо підтримуваної обгортки: базову Selenium fixture нескладно контролювати самостійно.

pytest залишається test runner незалежно від браузерної бібліотеки. Тому Selenium- і Playwright-тести можуть певний час співіснувати в одному Python-проєкті під час поступової міграції; їх достатньо розвести по зрозумілих packages, не переписуючи весь набір одразу.

5:00

Синхронізація середовища та pytest fixture для Chrome

Після зміни залежностей запускається uv sync, а фактично встановлена версія звіряється з lock-файлом. Якщо імпорт не працює або підтягнулась неочікувана версія, спочатку треба перевірити синхронізацію середовища, а не змінювати тестовий код навмання.

Створюється pytest fixture, яка ініціалізує webdriver.Chrome() і повертає driver тесту. Команди тесту надходять до browser driver, а він уже керує браузером. Аналогічно можна створювати Firefox, Edge або Safari driver, але для навчального сценарію достатньо Chrome.

Сучасний Selenium Manager підбирає сумісний driver автоматично, тому за звичайного локального запуску не потрібно вручну завантажувати executable й прописувати шлях. Це спрощує fixture, але версії Selenium і браузера все одно мають залишатися відтворюваними в CI.

Що змінилося після запису

Selenium Manager

У відеоУ відео Selenium Manager описано як автоматичний механізм, через який webdriver.Chrome() отримує потрібний driver без ручного шляху.

АктуальноСтаном на 2026-07-31 офіційна документація описує Selenium Manager як fallback, коли driver не передано або не знайдено. Він постачається з bindings від Selenium 4.6, підтримує керування браузерами від 4.11 і досі позначений як Beta.

Що змінилосяSelenium 4.6 для bundled driver management; Selenium 4.11 для automated browser management

Термін

Selenium Manager

Вбудований CLI-інструмент Selenium, який bindings використовують як fallback для автоматизованого керування browser drivers і, за потреби, браузерами.

10:00

Перший сценарій: `get`, `find_element` і CSS-селектори

Тест відкриває URL через driver.get(config.url), знаходить поля email і password та вводить значення через send_keys(). Кнопка входу знаходиться за CSS-селектором з атрибутом value, після чого викликається click().

На відміну від Playwright locators, у Selenium базовими операціями є find_element() і find_elements(). Перша повертає перший знайдений елемент або кидає NoSuchElementException, друга — колекцію всіх збігів. Якщо селектор неунікальний, find_element() може мовчки обрати не той вузол, тому локатор треба перевіряти на реальній сторінці.

Тип пошуку задається явно, наприклад By.CSS_SELECTOR. Якщо CSS-селектор усередині Python-рядка містить подвійні лапки, зовнішній рядок зручніше обгорнути одинарними, щоб не псувати синтаксис зайвим escaping.

15:00

Debugger і виправлення помилки в локаторі

Перший запуск падає з Unable to locate element: у селекторі переплутано дефіс і underscore. Замість додавання паузи селектор звіряється з уже робочим Page Object, помилка виправляється, а тест повторно запускається в debug mode.

На breakpoint можна виконувати код покроково через Step Over або продовжити Resume Program. Це дає змогу побачити, після якої саме браузерної команди змінився стан сторінки, і відокремити помилку локатора від помилки наступного кроку.

Після входу додається перевірка success message через is_displayed(). Така перевірка корисна як перший експеримент, але ще не робить тест стійким: вона читає стан елемента один раз і не очікує його появи.

20:00

Пошук проєкту й race condition після кліку

Сценарій розширюється: після авторизації тест знаходить поле пошуку, вводить Manufacture Light, відкриває проєкт і перевіряє заголовок сторінки. Локатори виносяться у змінні, щоб одне й те саме значення використовувалось для кліку та перевірки.

Очікування початкового завантаження документа не гарантує готовність динамічного UI. Після кліку Selenium одразу переходить до find_element(), тоді як потрібний компонент ще рендериться. У результаті тест падає не через дефект продукту, а через те, що тест швидший за інтерфейс.

is_displayed() тут не допомагає, якщо сам find_element() уже кинув exception. Синхронізацію треба будувати навколо повторного пошуку елемента, а не навколо одноразової перевірки рано знайденого об’єкта.

25:00

Чому implicit wait недостатньо

Перед аналізом очікувань виправляється ще одна причина падіння: регістр символів і точне значення атрибута мають збігатися з DOM. Це нагадування не списувати кожен NoSuchElementException на повільну сторінку — спочатку слід перевірити сам локатор.

driver.implicitly_wait(10) задає загальний час очікування для пошуку елементів. Такий механізм може дочекатися присутності вузла в DOM, але не виражає конкретний стан: елемент може існувати, залишаючись невидимим або недоступним для кліку.

Для сучасних динамічних сторінок урок рекомендує не покладатися на implicit wait. Тесту потрібна конкретна умова — visibility, clickability, selected state або зникнення — у конкретному місці сценарію.

Увага

Не змішуйте implicit та explicit waits

Офіційна документація Selenium попереджає, що їх поєднання спричиняє непередбачуваний фактичний час очікування.

Термін

Implicit wait

Глобальний timeout для кожної операції пошуку елемента в межах WebDriver session; значення за замовчуванням — 0.

30:00

`WebDriverWait` та `expected_conditions`

Явне очікування створюється як WebDriverWait(driver, timeout, poll_frequency=...). Timeout задає верхню межу, а poll_frequency — інтервал повторної перевірки. Значення треба підбирати без надмірного polling: частіші запити не лікують повільний продукт і можуть додати зайве навантаження браузеру.

Метод until() приймає конкретну умову з selenium.webdriver.support.expected_conditions, яку часто імпортують як EC. Серед типових умов: visibility_of_element_located, element_to_be_clickable, presence, invisibility і selected state.

До WebDriverWait можна передати ignored exceptions, наприклад NoSuchElementException або StaleElementReferenceException. Проте це працює лише тоді, коли пошук виконується всередині condition; якщо find_element() викликати раніше під час формування аргументу, exception виникне ще до старту polling.

Термін

Explicit wait

Polling loop, який очікує конкретну умову до timeout і завершується результатом condition або TimeoutException.

Приклад коду

Явне очікування видимого елемента

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

project_title = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located(
        (By.CSS_SELECTOR, '[data-testid="project-title"]')
    )
)
assert project_title.is_displayed()

Locator передається всередину expected condition, тому кожна спроба polling може повторно знайти актуальний DOM-вузол.

Очікуваний результат: Повертається видимий WebElement або після 10 секунд виникає TimeoutException.

Потрібно: selenium

35:00

Locator замість завчасно знайденого `WebElement`

find_element() є eager operation: команда одразу йде до WebDriver. Тому конструкція на кшталт EC.visibility_of(driver.find_element(...)) не захищає від раннього NoSuchElementException — елемент уже намагалися знайти.

Для елемента, який ще має з’явитися, використовується EC.visibility_of_element_located((By.CSS_SELECTOR, selector)). Condition отримує locator tuple і сам повторює пошук до успіху або timeout. Збереження By.CSS_SELECTOR у tuple також зменшує ризик переплутати тип локатора зі звичайним рядком.

Різниця принципова: is_displayed() робить одне звернення до стану вже знайденого element ID, тоді як explicit wait повторює перевірку. Саме тому очікування треба прив’язувати до спостережуваного стану, а не просто додавати після будь-якого пошуку.

40:00

Стабілізація сценарію та практичне завдання

Явні умови застосовуються до success message після логіну та до заголовка проєкту після навігації. Тепер падіння точніше описує проблему: не «клік не спрацював», а очікуваний елемент не став видимим за відведений час.

Для відтворюваного layout driver може максимізувати вікно або встановити фіксований розмір через set_window_size(). Локальний курсор також варто прибирати з області браузера: hover-стани, підказки та підсвічування можуть змінити DOM або перекрити ціль. У CI цей фактор зазвичай відсутній, але viewport усе одно треба задавати явно.

Практика після уроку: повторити простий Selenium-тест від fixture до входу й пошуку, а потім замінити одноразові is_displayed() у точках переходу на explicit waits із locator-based conditions.

Практика

Стабілізувати Selenium-сценарій

  1. Створіть pytest fixture з webdriver.Chrome() і гарантованим quit() після тесту.
  2. Відтворіть вхід і пошук проєкту через By.CSS_SELECTOR.
  3. Замініть перевірки після переходів на WebDriverWait з visibility_of_element_located.
  4. Навмисно зламайте один locator і переконайтеся, що падіння вказує на очікувану умову.

Результат: Тест проходить без sleep і падає з діагностичним TimeoutException, якщо цільовий locator неправильний.

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

  • Selenium Manager ↗Selenium · перевірено 2026-07-31

    Уточнює актуальний автоматичний пошук drivers і браузерів, згаданий під час створення fixture.

  • Waiting Strategies ↗Selenium · перевірено 2026-07-31

    Описує implicit та explicit waits і офіційне попередження про їх змішування.