Всем, привет.
В марте этого года вышла книга Бони Гарсия о Selenium WebDriver.
Ниже приведена глава, посвященная ожиданиям в Selenium. В планах сделать максимально полный перевод, думаю его делать по главам книги в том порядке, который мне будет казаться интересным и полезным.
Стратегия ожиданий (Wait strategy)
Веб-приложения - это клиент-серверные приложения, в которых клиент взаимодействует с веб-сервером при помощи браузера, веб-сервисы обычно это удаленныу хосты. Небольшая сетевая задержка может повлиять на надежность WebDriver теста. К примеру, в случае большой сетевой задержки или перегрузки серверов, медленный запрос может негативно повлиять на ожидаемое условие от WebDriver тестов. Также следует учитывать, что новые веб-приложения, как правило, динамические и асинхронные. В наши дни JavaScript поддерживает выполнение неблокирующих (т.е. асинхронных) операций, используя разные механизмы, такие как callbacks, promises, or async/await. Также мы можем извлекать данные с других серверов асинхронно, к примеру используя AJAX или REST сервисы.
Таким образом, первостепенно важным является иметь механизм паузы или ожидания определенного условия в наших WebDriver тестах. По этой причине Selenium WebDriver API предлагает различные стратегии ожиданий, три основные из которых: implicit, explicit и fluent.
Следующие разделы дают более детальное пояснения и показывают их примеры.
Внимание Для ожидания в Java вы можете думать об использовании Thread.sleep(). С одной стороны это простое решение, но с другой стороны это считается bad smell (weak sing/слабым сигналом), что может приводить к ненадежным тестам, поскольку условия ожидания могут измениться. Как общее правило, я настоятельно рекомендую вам не использовать его, вместо этого рассмотрите возможность использования вышеупомянутых стратегий ожидания, они более стабильны и надежны. |
Implicit Wait
Первая стратегия ожидания, которую предоставляет Selenium WebDriver называется неявным ожиданием (implicit wait). Этот механизм позволяет указать количество времени, прежде чем бросить исключение при поиске элемент. По умолчанию, это ожидание имеет значение ноль секунд (т.е. не ждет совсем). Но когда мы определяем значение для implicit wait, Selenium WebDriver опрашивает DOM, в течение указанного времени пытаясь найти элемент. Время опроса зависит от реализации драйвера и зачастую меньше пяти тысяч миллисекунд. Если элемент найден в указанное время, скрипт продолжается, в противном случае падает ошибка.
Пример 3-27 демонстрирует эту стратегию. Этот тест использует страницу (смотри рис. 3-12), которая динамически загружает несколько картинок внутри DOM. Поскольку эти изображения не доступны непосредственно перед загрузкой страницы, нам необходимо подождать, пока эти изображения загрузятся.
Пример 3-27. Тест использует неявное ожидание для ожидания загрузки рисунков на странице.
void testImplicitWait(){
driver.get ("https://bonigarcia.dev/selenium-webdriver-java/loading-images.html");
driver.manage ().timeouts (). implicitlyWait (Duration.ofSeconds (10)) ; (1)
WebElement landscape = driver.findElement (By.id ("landscape")); (2)
assertThat (landscape. getAttribute("src")).containsIgnoringCase ("landscape") ;
}
Пояснения:
В этой строке мы, перед тем как взаимодействовать с элементом, устанавливаем неявное ожидание в 10 секунд.
Здесь мы используем Selenium WebDriver API для поиска элемента.
Заметка Вы можете поиграть с этой функцией (методом), удалив неявное ожидание из теста (строка, обозначенная (1)). Если вы сделаете это, вы увидите, что тест упадет на втором шаге, где пытается найти элемент, с ошибкой NoSuchElementException. |
Следует также знать о различных минусах работы с неявными ожиданиями.
Первое - неявное ожидание работает только при поиске элементов.
Второе - мы не можем контролировать их настройку, поскольку их поведение зависит от настроек самого драйвера (ChromeDriver, MozilaGireFoxDriver и другие).
Третье - поскольку неявные ожидания применяются глобально (для настройки самого драйвера), это обычно увеличивает время выполнения всего теста.
По указанным причинам применение неявного ожидания в большинство случаев считаются плохой практикой, и лучше взамен ему использовать явные (explicit) и гибкие (fluent) ожидания
Явное ожидание (Explicit wait)
Вторая стратегия ожидания называется явным ожиданием (explicit), позволяет остановить выполнение теста на максимальное количество времени, пока специальное условие не будет выполнено. Для выполнения этой стратегии необходимо создать экземпляр WebDriverWait, используя конструктор WebDriverWait класса, в который необходимо передать агрумент экземпляр класса Duration, с помощью которого будет определяться продолжительность ожидания.
Selenium WebDriver предоставляет исчерпывающее количество методов класса ExpectedConditions, в которых реализованна работа для различных ожиданий, например дождаться
когда элемент будет отображатся на странице;
когда элемент будет кликабелен на странице и так далее.
Я рекомендую вам использовать функцию автозаполнения в вашем IDE для открытия всех методов (функций) класса ExpectedConditions, например на рисунке 3-13 представлен их список в Eclipse.
Пример 3-28 демонстрирует тест, который использует явное ожидание в нем. Мы используем метод presenceofElementLocated() для ожидания, пока рисунок не будет доступен на странице.
void testExplicitwait() {
driver. get ("https://bonigarcia.dev/seleniumwebdriver-java/loading-images.html");
WebDriverWait wait = new WebDriverWait (driver, Duration. ofSeconds (10)); (1)
WebElement landscape = wait.until (ExpectedConditions.presenceOfElement Located(By.id("landscape"))); (2)
assertThat (landscape.getAttribute ("src")).containsIgnoringCase("landscape");
}
В данной строке мы создали экземпляр WebDriverWaiе ожидания и установили тайм-аут в 10 секунд.
В этой строке мы явно ждем заданного условия (присутствия необходимого элемента) за счет вызова метода until() у WebDriverWait объекта и передаем методу until(), в качестве переменного условия для ожидания конкретного элемента с id = "landscape".
Пример 3-29 показывает другой тест, использующий явное ожидание. Этот тест использует другую веб-страницу, называющуюся “Демонстрация калькулятора”, которая содержит интерфейс базового калькулятора. В этом тесте установлено ожидание на отображание конкретного результа по итогам выполнения арифметических функций (сложение 1 с 3), рисунок 3-14 показывает скриншот этой страницы.
Пример 3-29
void testSlowCalculator() {
driver.get("https://bonigarcia.dev/selenium-webdriver-java/slow-calculator.html");
//1+3 =
driver. findElement (By.xpath("//span[text () ='1']")). click(); (1)
driver. findElement(By.xpath("//span[text () ='+']")).click();
driver. findElement(By.xpath("//span[text () ='3']")).click():
driver. findElement (By.path("//span[text () ='=']")). click();
//…..should be 4, wait for it
WebDraverWait wait = Duration. ofSeconds(10)):
wait.until (ExpectedConditions.textToBe(By.className("screen"),"4") ) ; (2)
}
В этой строке и в последующих трех, мы используем XPath локаторы, чтобы кликнуть на кнопки, соответствующее операции “1+3=”;
В данной строке мы явно ждем, значения текста у элемента с именем класса ‘screen’, равного 4.
Fluent Wait (Гибкое ожидание)
Последняя стратегия это fluent wait (гибкое ожидание). Этот механизм ожидания, который является разширением возможностей явных ожиданий (explicit wait). Другими словами, мы используем fluent wait (гибкое ожидание) для остановки теста до выполнения определенных условий, но в fluent wait (гибком ожиданим) у нас есть возможность более тонкой настройки этого ожидания [такие как установка значения для тайм-айта, установка значения для переодичности опроса, а также мы можем указывать эксепшен, который необходимо игнорировать].
В таблице 3-12 представлены методы, доступные в FluentWait. Как следует из названия, этот класс предоставляет гибкий API, и, следовательно, мы можем связать несколько вызовов в одной строке. Пример 3-30 показывает тест, использующий плавающее ожидание.
Таблица 3-12. Методы плавающего (fluent) ожидания.
Пример 3-30 Тест, использующий гибкое ожидание
void testFluentWait() {
driver. get ("https://bonigarcia.dev/seleniumwebdriver-java/loading-images.html");
Wait<WebDriver> wait = new FluentWait<> (driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofSeconds(1))
.ignoring (NoSuchElementException.class); (1)
WebElement landscape = wait.until(ExpectedConditions
.presence0fElementLocated(By. id ("landscape"))) ;
assertThat (landscape.getAttribute ("src")).containsIgnoringCase ("landscape") ;
}
Как вы можете видеть, тест очень похож на Пример 3-28, но, используя экземпляр класса FluentWait, мы может устанавливать дополнительные характеристики, такие как перидичность опроса (здесь установлен тайм-аут на 10 секунд и указано, что опрос будет осуществляться каждую секунду в течение этих 10 секунд).
Заметка Класс WebDriverWait (представленный в предыдущем разделе) расширяет класс FluentWait. Таким образом, вы можете использовать все методы, показанные в таблице 3-12, и также для явного ожидания. |
Зависимые функции в Selenium WebDriver
В дополнение к описанным стратегиям ожиданий, есть другие дополнительные возможности в Selenium WebDriver о которых вы должны знать.
Loading strategies
Selenium WebDriver предоставляет разные подходы для ожидания загрузки страницы. Эта функция доступна благодаря возможностям браузера (Chrome0ptions, Firefox0ptions, etc.). По этой причине я объясняют эту функцию в другой главе “Стратегии загрузки страницы”. [пока еще не переведена]
Timeouts
Selenium WebDriver предоставляет указание максимального времени загрузки страницы и скрипта. Я объясняю эту функцию в разделе «Тайм-ауты». [пока еще не переведена]