Продолжение перевода неофициальной документации Selenium для Python.
Оригинал можно найти здесь.

Содержание:


1. Установка
2. Первые шаги
3. Навигация
4. Поиск элементов
5. Ожидания
6. Объекты Страницы
7. WebDriver API
8. Приложение: Часто Задаваемые Вопросы

5. Ожидания


В наши дни большинство веб-приложений используют AJAX технологии. Когда страница загружена в браузере, элементы на этой странице могут подгружаться с различными временными интервалами. Это затрудняет поиск элементов, если элемент не присутствует в DOM, возникает исключение ElementNotVisibleException. Используя ожидания, мы можем решить эту проблему. Ожидание дает некий временной интервал между произведенными действиями — поиске элемента или любой другой операции с элементом.

Selenium WebDriver предоставляет два типа ожиданий — неявное (implicit) и явное (explicit). Явное ожидание заставляет WebDriver ожидать возникновение определенного условия до произведения действий. Неявное ожидание заставляет WebDriver опрашивать DOM определенное количество времени, когда пытается найти элемент.

5.1 Явные ожидания


Явное ожидание — это код, которым вы определяете какое необходимое условие должно произойти для того, чтобы дальнейший код исполнился. Худший пример такого кода — это использование команды time.sleep(), которая устанавливает точное время ожидания. Существуют более удобные методы, которые помогут написать вам код, ожидающий ровно столько, сколько необходимо. WebDriverWait в комбинации с ExpectedCondition является одним из таких способов.

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

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

Этот код будет ждать 10 секунд до того, как отдаст исключение TimeoutException или если найдет элемент за эти 10 секунд, то вернет его. WebDriverWait по умолчанию вызывает ExpectedCondition каждые 500 миллисекунд до тех пор, пока не получит успешный return. Успешный return для ExpectedCondition имеет тип Boolean и возвращает значение true, либо возвращает not null для всех других ExpectedCondition типов.

Ожидаемые условия
Существуют некие условия, которые часто встречаются при автоматизации веб-сайтов. Ниже перечислены реализации каждого. Связки в Selenium Python предоставляют некоторые удобные методы, так что вам не придется писать класс expected_condition самостоятельно или же создавать собственный пакет утилит.

  • title_is
  • title_contains
  • presence_of_element_located
  • visibility_of_element_located
  • visibility_of
  • presence_of_all_elements_located
  • text_to_be_present_in_element
  • text_to_be_present_in_element_value
  • frame_to_be_available_and_switch_to_it
  • invisibility_of_element_located
  • element_to_be_clickable — it is Displayed and Enabled.
  • staleness_of
  • element_to_be_selected
  • element_located_to_be_selected
  • element_selection_state_to_be
  • element_located_selection_state_to_be
  • alert_is_present

from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID,'someid')))

Модуль expected_conditions уже содержит набор предопределенных условий для работы с WebDriverWait.

5.2 Неявные ожидания


Неявное ожидание указывает WebDriver'у опрашивать DOM определенное количество времени, когда пытается найти элемент или элементы, которые недоступны в тот момент. Значение по умолчанию равно 0. После установки, неявное ожидание устанавливается для жизни экземпляра WebDriver объекта.

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

Перейти к следующей главе: Объекты Страницы

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

Комментарии (7)


  1. knekrasov
    14.12.2015 18:35
    +1

    Используем на проекте selenium для тестов веб-морды. И честно говоря, поддержка таких тестов — это сущий ад. Я допускаю, что мы просто не умеем их готовить (хотя я так не думаю).

    Проблемы, с которыми лично я столкнулся:

    • Хрупкость тестов (завязка на верстку)
    • Тесты тяжело отлаживать (система, которую тестируем — это черный ящик, скриншоты наше все)
    • Неочевидность проблем (динамический контент, неявные состояния страницы и тп)
    • Баги в самом selenium, когда часть функционала проще переписать на чистом JS и выполнить в контексте браузера.
    • Код теста почти никогда не будет написан в терминах тестируемой функциональности


    В связи с этим вопрос в пустоту: а как на самом деле делают автоматизированные тесты для веб-сайтов?


    1. biomaks
      14.12.2015 20:55

      С UI тестами все так и обстоит, но приходится иметь дело с тем, что есть.
      Хрупкость тестов — частично решается использованием page objects, и попыткой договорится с девелоперами фронта
      Отлаживать да, все по старинке, точки останова, скриншоты и т.д.
      С неочевидностью как раз помогут явные ожидания описанные в этой статье
      Баги есть, но их на самом деле не очень много, и фиксятся они достаточно оперативно
      По поводу терминов тестируемой функциональности я не очень понял.

      И если не сильно завязаны на python, посмотрите на Selenide он на java, и он частично решает вышеописанные проблемы.


    1. darthkwisatzhaderach
      15.12.2015 08:10

      На мой взгляд распространенная ошибка — попытка автоматизировать тестирование функциональности, которая активно модифицируется. Автоматизировать нужно устоявшуюся функциональность, тогда и проблем с поддержанием будет меньше.


      1. knekrasov
        15.12.2015 10:59

        Ну тогда получается, что Selenium бесполезен? На мой взгляд, верстка меняется чаще всего. То, что крутится на бекэнде, как поменялось server api заказчик скорее всего не видит, а вот требования к внешнему виду — вещь наиболее переменчивая. Получается, что валидировать утверждение «Сайт работает как положено» со стороны UI бессмысленно.
        Проще покрыть тестами серверную часть, покрыть интеграционными тестами server API (чаще всего RESTful-like) и каким-то чудом написать отдельные unit-тесты для JS-части.


        1. darthkwisatzhaderach
          15.12.2015 15:50

          Никто не мешает использовать локаторы, которые не завязаны на верстку (осуществлять поиск элементов по уникальным идентификаторам). Мой коментарий больше про то, что ошибка автоматизировать там, где активно меняется бизнес логика. Все остальное лечится тест-дизайном.


          1. knekrasov
            15.12.2015 18:29

            Локаторы — вещь не идеальная.

            Чем больше у страницы неявных состояний, тем сложнее тест (примеры: один виджет подгрузился, второй спрятался, в третий прилетели данные; Bootstrap'овское модальное окошко начало исчезать и с точки зрения DOM API оно уже скрылось, но по факту элементы под ним все еще не кликабельны и тд и тп).

            Можно ли где-нибудь найти информацию именно о тест-дизайнах именно в контексте Selenium? Что-то вроде best practices.


            1. darthkwisatzhaderach
              15.12.2015 19:25

              То что вы описываете, это фоновые запросы к серверной части (AJAX). По факту использование этой технологии сейчас становится стандартом при разработке web-приложений. На страницах с такими запросами очень важно отслеживать состояние DOM, вернее следить за тем, чтобы DOM не обновлялся между моментом нахождения элемента и моментом взаимодействия с ним.

              Есть такое расширение как Selenium WebDriver Support Classes для работы с UI. Там есть набор методов для определения состояния элементов (https://seleniumhq.github.io/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html). В сочетании с wait.until можно безопасно дождаться практически любого состояния страницы. Реализация Selenium WebDriver Support Classes есть и для Java, C# и других популярных языков.