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

от автора

Привет, дорогие коллеги! В прошлой статье мы разобрали с вами один из наиболее удобных и гибких, на мой взгляд, способов построить фреймворк для проекта по автоматизации тестирования на 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, 'Пароль не может быть пустым, дружочек')) 

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


ссылка на оригинал статьи https://habr.com/ru/articles/935900/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *