🐛 Частые ошибки с локаторами

← К оглавлению урока

⚡ Топ-5 ошибок с локаторами

  1. Хрупкий XPath из DevTools — сломается при любом изменении HTML.
  2. CLASS_NAME с пробеломBy.CLASS_NAME, "btn btn-primary" выбросит исключение.
  3. find_element() без try-except — тест падает с необработанным NoSuchElementException.
  4. is_displayed() путают с существованием — элемент может быть найден, но скрыт.
  5. XPath @class с составным классом//*[@class="btn btn-primary"] не найдёт элемент с дополнительными классами.

Ошибка 1: Хрупкий XPath из DevTools

«Copy XPath» из DevTools генерирует абсолютный путь. Сломается при любом изменении HTML-структуры.
# ПЛОХО: XPath, скопированный из DevTools
driver.find_element(
    By.XPATH,
    "/html/body/div[2]/div[1]/div/form/div[1]/div/input"
)
# Упадёт, если между div добавить ещё один элемент

# ХОРОШО: XPath на основе стабильных атрибутов
driver.find_element(By.XPATH, "//*[@id='username']")
driver.find_element(By.XPATH, "//input[@name='username']")
driver.find_element(By.XPATH, "//button[text()='Login']")

Ошибка 2: By.CLASS_NAME с составным классом

By.CLASS_NAME принимает только один класс. Пробел вызовет InvalidSelectorException.
<!-- HTML -->
<button class="btn btn-primary">Login</button>

# ПЛОХО: составной класс вызовет исключение
driver.find_element(By.CLASS_NAME, "btn btn-primary")
# → InvalidSelectorException

# ХОРОШО: один класс
driver.find_element(By.CLASS_NAME, "btn-primary")

# ЕЩЁ ЛУЧШЕ: CSS-селектор с несколькими классами
driver.find_element(By.CSS_SELECTOR, ".btn.btn-primary")

Ошибка 3: find_element() без обработки исключения

# ПЛОХО: тест падает с необработанным исключением
element = driver.find_element(By.ID, "maybe-not-here")
# → NoSuchElementException: no such element

# ХОРОШО: явная обработка
from selenium.common.exceptions import NoSuchElementException

try:
    element = driver.find_element(By.ID, "maybe-not-here")
    assert element.is_displayed()
except NoSuchElementException:
    assert False, "Элемент #maybe-not-here не найден на странице"

# ЕЩЁ ВАРИАНТ: find_elements() для проверки существования
elements = driver.find_elements(By.ID, "maybe-not-here")
assert len(elements) > 0, "Элемент не найден"

Ошибка 4: Путаница is_displayed() и существованием элемента

<!-- HTML: элемент есть в DOM, но скрыт -->
<button id="myButton" style="display: none;">Кнопка</button>

# ПЛОХО: think find_element() гарантирует видимость
button = driver.find_element(By.ID, "myButton")
# Элемент найден — но он скрыт!
button.click()  # Может вызвать ElementNotInteractableException

# ХОРОШО: явная проверка видимости
button = driver.find_element(By.ID, "myButton")
assert button.is_displayed(), "Кнопка должна быть видима"
button.click()
Правило: find_element() находит элемент даже если он скрыт. is_displayed() — отдельная проверка. В автотестах всегда проверяйте видимость перед кликом.

Ошибка 5: XPath @class с составным классом

<!-- HTML -->
<button class="btn btn-primary active">Login</button>

# ПЛОХО: точное совпадение @class требует ВСЕ классы в правильном порядке
driver.find_element(By.XPATH, "//*[@class='btn-primary']")
# → NoSuchElementException (класс не один!)

# ХОРОШО: contains() для частичного совпадения
driver.find_element(By.XPATH, "//*[contains(@class, 'btn-primary')]")

# ЕЩЁ ЛУЧШЕ: CSS-селектор
driver.find_element(By.CSS_SELECTOR, ".btn-primary")

Ошибка 6: Нет ожидания перед поиском

Страница ещё не загрузилась, а тест уже ищет элемент — получает NoSuchElementException. Решение: явные ожидания (урок 07).
# ПЛОХО: нет ожидания
driver.get("https://some-page.com")
element = driver.find_element(By.ID, "dynamic-element")
# Упадёт, если элемент появляется динамически

# ХОРОШО: явное ожидание (подробнее — урок 07)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "dynamic-element"))
)

Ошибка 7: find_elements() и доступ по индексу без проверки

# ПЛОХО: доступ к элементу без проверки длины
cards = driver.find_elements(By.CSS_SELECTOR, ".card")
first_card = cards[0]  # IndexError если список пустой

# ХОРОШО: проверить длину перед доступом
cards = driver.find_elements(By.CSS_SELECTOR, ".card")
assert len(cards) > 0, "Карточки не найдены"
first_card = cards[0]