Search
Write a publication
Pull to refresh

Гайд по правильным ожиданиям в UI — тестах. SeleniumWebDriverWait и Expected Conditions

Level of difficultyEasy
Reading time4 min
Views179

Привет, дорогие коллеги! В прошлой статье мы разобрали с вами один из наиболее удобных и гибких, на мой взгляд, способов построить фреймворк для проекта по автоматизации тестирования на Python. В качестве примера я приводил автотесты для API. Сегодня же я хочу поделиться с вами небольшим гайдом (или шпаркалкой, кому как удобнее) по одному из аспектов UI - тестирования. Если быть конкретным, речь идет о грамотных ожиданиях в тестах.
Наверное, каждый, кто уже более или менее погрузился в автоматизацию, уже не раз слышал либо понял сам, что использовать в тестах функцию sleep из стандартного модуля Python - это плохая практика, да и вообще моветон. Так вот. Для того, чтобы избежать косых вглядов коллег и просто не напороться в один момент на вилы в собственных тестах, предлагаю вам разобраться, как и когда использовать специальный модуль Selenium-a - Expected Conditions, который управляет теми самыми ожиданиями. Начнем.

БАЗА. Что, как и зачем?
В Selenium есть два основных типа ожидания: неявное (implicity_wait) и явное (WebDriverWait).

  • Неявное ожидание. Когда мы говорим Selenium: "Если ты при открытии страницы браузера сразу не можешь найти искомый элемент, не кричи сразу "тревога, мы все уронили", а сначала подожди n секунд, и уже потом, если элемент так и не появился, выдавай ошибку". Конструкция выглядит так: browser. implicity_wait(n). Вместо n, как вы уже догадались, нужное нам количество секунд. Рекомендую это также выносить в фикстуру вместе с инициализацией browser (о фикстурах и файле conftest.py я рассказывал в прошлой статье). Например:

Потом просто передаем эту фикстуру в качестве аргумента в конкретный тест. Очень удобно
Потом просто передаем эту фикстуру в качестве аргумента в конкретный тест. Очень удобно
  • Явное ожидание. Мы говорим Selenium: "Жди n секунд, пока не выполнится конкретное условие/событие (expected_conditions), и потом проверяй это условие". Такое подход наиболее гибкий и является стандартом. Выглядит это примерно следующим образом:

#Сначала импорт нужных модулей
from selenium.webdriver.support.ui import WebDriverWait
# as EC принято называть для сокращения длинного "expected_conditions"
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# Инициализируем ожидатор:) и говорим ему жди 10 секунд
wait = WebDriverWait(browser, 10)
element = wait.until(EC.условие(By.локатор, "значение_локатора"))

Это примерный базовый синтаксис для понимания конструкции в целом. Далее я как раз расскажу о том, какие же условия бывают.

Примечание: приведенная ниже классификация является исключительно авторской и представлена для удобства восприятия.

Группа условий № 1. Проверка присутствия видимости элемента

Как правильно наиболее часто используемая группа условий (на моей практике).

  • presence_of_element_located((locator))
    - Что делает: Ждет, пока элемент появился в DOM-дереве страницы.
    - Когда использовать:
    -- Когда нужно убедиться, что элемент загрузился в HTML - коде
    -- Когда работаем с "невидимыми" элементами
    - Доп. заметки:
    -- Элемент может быть в DOM - дереве, но невидим на странице
    -- Самое "слабое" ожидание, но самое быстрое, если видимость не имеет значения

  • visability_of_element_located((locator))
    - Что делает: Ждет, пока элемент не только появится в DOM - дереве, но и станет видимым на странице
    - Когда использовать:
    -- Практически в 90% случаев. Чтобы кликнуть, ввести текст, как-то повзаимодействовать с элементом, нужно, чтобы он появился.

  • element_to_be_clickable((locator))
    - Что делает: Ждет, пока элемент станет видимым И активным (enabled).
    - Когда использовать:
    -- Всегда перед кликом на кнопку, ссылку или чекбокс. Фактически, решает проблему, когда кнопка уже видима, но еще неактивна (задизейблена).
    - Доп. заметки:
    -- На мой взгляд, самое сильное и надежное ожидание перед кликом.

Группа № 2. Проверка состояния элемента

Используются для проверки атрибутов, текста и т.д.

  • text_to_be_present_in_element((locator), ''ожидаемый текст")
    - Что делает: Ждет, пока внутри указанного элемента появится ожидаемый текст
    - Когда использовать:
    -- Когда ждем, пока на странице обновится какой-то счетчик, статус или сообщение после выполнения определенного действия. Например: после добавления товара в корзину, мы ждем, пока в элементе с id "cart_counter" появится текст "1".

  • invisibility_of_element_located((locator))
    - Что делает: Ждет, пока элемент станет невидимым или полностью исчезнет из DOM.
    - Когда использовать:
    -- Когда ждем, пока исчезнет какой-нибудь спиннер загрузки (лоадер)
    -- Когда проверяем, что после удаления элемент действительно пропал со страницы.

Группа № 3. Работа с alert -ами

Это группа специализированных ожиданий для работы со всплывающими окнами.

  • alert_is_present()
    - Что делает: Ждет, пока на странице не появится стандартное окно alert, confirm или prompt.
    - Когда использовать:
    -- При тестировании функционала, вызывающего данные окна.
    - Доп. заметки:
    -- Этот тип ожидания (метод ожидания) не принимает локатор. Он возвращает объект alert, с которым мы будем работать (alert.accept(), alert.dismiss())

С классификацией, кажется, все. Как все мы знаем, прочитать информацию это одно, совсем другое - увидеть на примере. Поэтому набросал для вас небольшой пример использования:

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

# Представим, что тестируем форму логина
LOGIN_BUTTON = (By.CSS_SELECTOR, '#login-button')
USERNAME_INPUT = (By.ID, 'username')
ERROR_MESSAGE = (By.CLASS_NAME, 'error-message')
LOAD_SPINNER = (By.CSS_SELECTOR, '.loader')

# Инициализируем ждуна, с неявным типом ожиданием
wait = WebDriverWait(browser, 15)

# Вводим имя пользователя (применяем ожидание появления элемента на странице)
username = wait.until(EC.visability_of_element_located(USERNAME_INPUT))
username.send_keys('testuser')

# Кликаем на кнопку (после того, как дождались, пока она стала кликабельной)
login_button = wait.until(EC.element_to_be_clickable(LOGIN_BUTTON))
login_button.click()

# Теперь ждем, пока исчезнет спиннер загрузки, который появился после клика
load_spinner = wait.until(EC.invisibility_of_element_located(LOAD_SPINNER))

# К примеру мы не ввели пароль и ожидаем появления сообщения об ошибке после спиннера
wait.untill(EC.text_to_be_present_in_element(ERROR_MASSAGE, 'Пароль не может быть пустым, дружочек'))

Этот пример максимально простой и показывает, как можно комбинировать различные типы ожидания, чтобы наши автотесты не "моргали". На этом сегодня, пожалуй, у меня все. Конструктивная критика и замечания приветствуются, плюсы в карму ценятся, ибо надеюсь кому-то изложенный мной материал будет полезен. Всем добра!

Tags:
Hubs:
0
Comments0

Articles