Selenium WebDriver: полный разбор

Кратко о Selenium и его создателях

С начала Нулевых, с активным внедрением JavaScript, у QA-инженеров возникла потребность в отдельном приложении для тестирования кода на JS. Поэтому Джейсон Хаггинс, уже тогда видный деятель QA-комьюнити, создал в 2004 году — нет, еще не Selenium — а только JavaScriptTestRunner. 

Наверное, эта выдающаяся личность требует отдельного упоминания.

Хаггинс, создатель Selenium
Джейсон Хаггинс создатель Selenium

Как характеризуют его в глобальном комьюнити, «невероятно мудр, колоссально опытен, у него бывают гениальные озарения, и он очень упрям». Сейчас он делает роботов для тестирования тачскринов — Tapster Robotics, если интересно.

Джейсон Хаггинс - Tapster Robotics
Один из роботов Tapster Robotics

Кроме Selenium, он активно участвовал в создании Appium

С самого начала Selenium оказался мощной и полезной штукой, и Хаггинс решил открыть код и передать Selenium Core под опеку комьюнити. Далее Пол Хамман «допилил» проект и назвал Selenium Remote Control (RC, также известен как Selenium 1). Патрик Лайтбоди присоединил к проекту Selenium Grid для параллельного запуска тестов, а японец Шиная КасатаниSelenium IDE для записи/воспроизведения. Ну и дополнил этот «оркестр» Саймон Стюарт, который создал, собственно, предмет нынешней статьи — Selenium WebDriver, после чего взял на себя общее управление проектом Selenium, и с той поры остается главой Selenium Project

Иерархия Selenium WebDriver 4

Постепенно Selenium превратился в мощнейший пакет с множеством функций, и спустя 20 лет после создания остается, в принципе, все еще главным инструментом тестирования веба, как бы стандартом в этой сфере. Состоит из 3 главных компонентов:

  • Привязки к языку — (Selenium Language Bindings, байндинги) — наборы классов и методов для языков программирования (то есть для написания автотестов веб-сайтов). В данное время WebDriver поддерживает Java, C#, Python, Ruby, JavaScript (то есть все более-менее распространенные ЯПы в QA).
  • WebDriver API — набор классов и методов для взаимодействия с браузерами Chrome, Firefox, Edge и пр. То есть для управления навигацией, кнопками, вкладками, окнами, получения URL и кода веб-страницы, ввода данных в поля, операций с чекбоксами и радиокнопками, списками и пр, и пр.
  • Имплементация WebDriver — интерфейс для программного обращения к веб-браузерам. Управляет коммуникацией между браузером и привязкой-«байндингом» (в первом пункте выше). Автоматизирует элементы в DOM и оперирует ими. 
Клиентские библиотеки Selenium Selenium Webdriver 4
Клиентские библиотеки Selenium

В данное время Selenium 4 WebDriver полностью совместим с требованиями W3C по браузерам. Уже с 2020 года не нужны специальные «твики» в Selenium-сценариях, чтобы они работали во всех браузерах, потому что все работает «по стандартному протоколу» W3C. Поэтому есть смысл полностью переходить на 4-ю версию Selenium.

Как работает Selenium через клиентские библиотеки
Как работает Selenium

Начиная с версии 4.6.0 [последняя версия — 4.10], Selenium Manager управляет всеми нужными браузер-драйверами, без внешних библиотек типа WebDriverManager; на машину ставится соответствующий драйвер, и выполняются тесты.

Итак, этой строчкой кода мы запускаем Chrome:

WebDriver driver = new ChromeDriver();

И получаем доступ ко всем методам. Теперь посмотрим на иерархию WebDriver:

Selenium WebDriver 4 - иерархия
Иерархия Selenium WebDriver 4

Класс RemoteWebDriver

Начнем с класса RemoteWebDriver — это полностью имплементированный класс интерфейса, расширяемый каждый классом BrowserDriver в Selenium-фреймворке.

RemoteWebDriver Class
Класс RemoteWebDriver

В классе RemoteWebDriver имеются следующие вложенные (nested) классы:

  • RemoteTargetLocator — полностью имплементированный класс интерфейса WebDriver.TargetLocator.
RemoteTargetLocator
RemoteTargetLocator
  • RemoteWebDriverOptions — полностью имплементированный класс интерфейса WebDriver.Options. В этом классе есть вложенные:
RemoteWebDriverOptions
RemoteWebDriverOptions
  • RemoteTimeouts — этот класс имплементирует интерфейс WebDriver.Timeouts, с полной имплементацией всех его абстрактных методов:
RemoteTimeouts
RemoteTimeouts
  • RemoteWindow — имплементирует интерфейс WebDriver.Window с полной имплементацией всех его абстрактных методов.

Вложенные классы в RemoteWebDriver:

Вложенные классы в RemoteWebDriver
Вложенные классы в RemoteWebDriver

Как работать с классом RemoteWebDriver

Конструкторы для создания экземпляров класса:

  • RemoteWebDriver(ICapabilities)
  • RemoteWebDriver(Uri, ICapabilities)
  • RemoteWebDriver(ICommandExecutor, ICapabilities)
  • RemoteWebDriver(Uri, ICapabilities, TimeSpan)

Далее в примере используется RemoteWebDriver(Uri, ICapabilities) для запуска тестов на популярной платформе LambdaTest. Реализация на другой платформе может отличаться в зависимости от конфигурации — но принципы работы с классомRemoteWebDriver остаются теми же.

Тест Selenium на платформе LambdaTest
Выполнение теста Selenium на внешней платформе

Класс RemoteWebDriver имплементирует такие интерфейсы:

  • WebDriver
  • JavaScriptExecutor
  • TakesScreenshot
  • HasVirtualAuthenticator
  • PrintsPage
  • HasCapabilities
  • Interactive

Далее подробнее.

Интерфейс WebDriver

Это «ядро» WebDriver, ключевой интерфейс со всеми нужными методами; и вложенными интерфейсами. Все эти методы симулируют действия пользователя в браузере.

Ниже UML-диаграмма интерфейса WebDriver в Selenium WebDriver 4:

Абстрактные методы и nested-интерфейсы в WebDriver
Абстрактные методы и вложенные интерфейсы в интерфейсе WebDriver

Далее перечислим абстрактные методы.

get(String url)Метод возвращает пустое значение; для перехода по URL в параметре метода
getCurrentUrl()Возвращает текущий URL страницы
getTitle()Тайтл (title) текущей страницы
findElements(By by)Список веб-элементов для локатора, вызываемого By-классом Selenium’а (абстрактный класс)
findElement(By by)Веб-элемент (как выше, но один)
getPageSource()HTML-код последней загруженной страницы в виде DOM
close()Закрывает текущее окно (и закрывает браузер, если это было последнее окно)
quit()Прекращает сессию драйвера, закрывая каждое связанное  ней окно
getWindowHandles()Возвращает список дескрипторов окон (window handles), через них можно получить доступ ко всем открытым окнам этого экземпляра WebDriver
getWindowHandle()Возвращает текущий дескриптор окна (которое сейчас в фокусе) в текущем экземпляре WebDriver, чтобы потом переключиться на это окно.
switchTo()Возвращает TargetLocator для выбора фрейма или окна и отправки ему команд
navigate()Абстракция, позволяющая перейти по URL и по истории браузера
manage()Возвращает интерфейс Options

Как работает WebDriver Interface

В нем методы взаимодействия со страницей через браузер. Сначала нужно импортировать нужные библиотеки и создать экземпляр WebDriver-объекта.

Как работать с интерфейсом WebDriver
Работа с интерфейсом WebDriver

Переходим ко вложенным (nested) интерфейсам.

Вложенные интерфейсы в WebDriver

Nested-интерфейсы в интерфейсе WebDriver
Вложенные интерфейсы в интерфейсе WebDriver

Интерфейс Window

Через этот интерфейс идут операции с текущим окном. 

Nested-интерфейс - WebDriver.Window
Вложенный интерфейс — WebDriver.Window

В нем абстрактные методы, полностью имплементированные классом RemoteWebDriver:

getSize()Возвращает внешние размеры текущего окна
setSize(Dimension dimension)Текущие и внешние размеры окна. (Метод отвечает window.resizeTo() в JavaScript)
getPosition()Возвращает позицию текущего окна относительно верхнего левого угла экрана
setPosition(Point targetPosition)Передвигает окно (устанавливает его позицию) относительно левого верхнего угла экрана; соответствует window.moveTo() в JS
maximize()Максимизирует окно (если еще не развернуто)
minimize()Сворачивает окно в панель задач (если не свернуто)
fullScreen()Разворачивает окно на весь экран (если еще не)

Применение: создается экземпляр интерфейса — созданием нового объекта через вызов имплементирующего класса. После создания объекта:

Работа с Window
Работа с Window-интерфейсом

Интерфейс Options

Это доступ к меню браузера. 

  • Добавлять, получать, и удалять cookie
  • Выставлять таймауты в браузере
  • Управлять окном
  • Выводить логи, разных типов
Вложенный интерфейс в WebDriver - WebDriver.Options
Вложенный интерфейс в WebDriver-интерфейсе — WebDriver.Options

Список абстрактных методов, полностью имплементированных в классе RemoteWebDriver:

addCookie (Cookie cookie)Добавляет cookie в текущий контекст браузера. Для идентификации пользователя и хранения информации о нем. В этом методе нужен параметр. Если доменное имя в cookie пустое, то cookie относится к домену текущего документа.
deleteCookieNamed (String name)Метод удаляет cookie с указанным в параметре именем из текущего домена
deleteCookie (Cookie cookie)Удаляет cookie из “cookie.jar”, игнорируя его домен
deleteAllCookies()Удаляет все cookie текущего домена
getCookies()Возвращает набор cookie по текущему домену
getCookieNamed(String name)Возвращает cookie с указанным именем. Если имя не указано, вернет null
timeouts()Возвращает интерфейс управления таймаутами браузера
window()Возвращает интерфейс управления текущим окном

Применение: нужно создать экземпляр интерфейса WebDriver через создание нового объекта вызовом имплементирующего класса. После создания объекта просто используется Options-интерфейс:

Интерфейс Options в WebDriver
Options-интерфейс в WebDriver

Интерфейс Navigation

Методы для истории в браузере и навигации по URL:

  • Назад/Вперед в истории
  • Перейти на указанный URL
  • Обновить страницу
WebDriver.Navigations - вложенный интерфейс в WebDriver
WebDriver.Navigations — вложенный интерфейс в WebDriver
back()Метод симулирует нажатие кнопки Назад в браузере
forward()Кнопки Вперед
to(String url)Переход по URL (в String-формате в параметре)
to(URL url)Перегруженный метод to(String url), то же действие (в параметре в URL-формате)
refresh()Обновляет страницу

Как и во всех предыдущих примерах, создается экземпляр интерфейса WebDriver через создание нового объекта вызовом имплементирующего класса. После создания объекта:

Работа с интерфейсом Navigations в WebDriver
Navigations в WebDriver

Интерфейс TargetLocator

Методы отправки команд в фреймы и окна:

  • Работа с окнами и табами браузера
  • Фреймами
  • А также Alerts в браузере
Интерфейс WebDriver.TargetLocator
Вложенный интерфейс WebDriver.TargetLocator

Абстрактные методы, имплементируемые классом RemoteTargetLocator (вложенным в RemoteWebDriver):

frame(int index)Метод выбирает фрейм по его индексу (начиная с 0). После того как фрейм выбран, все последующие вызовы экземпляра WebDriver будут выполнены к этому фрейму. Если фрейм не выбран, вернется NoSuchFrameException.
frame(String nameOrId)Этот метод выбирает фрейм по его имени или ID, в параметре. Если имя (ID) не уникальное на странице, будет выбран первый найденный. После выбора фрейма все последующие вызовы экземпляра будут выполнены к этому фрейму. Если фрейм не найден, будет возвращено NoSuchFrameException.
frame(WebElement frameElement)Метод выбирает фрейм, используя ранее найденный WebElement. После выбора фрейма последующие вызовы экземпляра WebDriver будут выполнены к этому фрейму. Так как этот метод принимает WebElement как параметр, то если фрейм не найден, могут быть выброшены следующие эксепшены:
NoSuchFrameException — если элемент не iFrame и не Frame.
StaleElementReferenceException — если этот WebElement по какой-то причине находится «вне дерева» DOM, потому что был удален из DOM или не прикреплен к документу.
parentFrame()Переводит фокус на верхний (родительский) фрейм. Контекст останется неизмененным, если текущий контекст — самого верхнего уровня. 
window(String nameOrHandle)По имени окна или дескриптору, возвращенному методом getWindowHandle(). Метод переключает фокус будущих команд текущего экземпляра драйвера на окно с указанным именем или дескриптором. Если не найдено, то выбросит эксепшен NoSuchWindowException.
newWindow(WindowType typeHint)Метод создает новое окно или вкладку по Window Type (TAB или WINDOW), указанному в параметре метода, и переключает фокус будущих команд на новое окно.
defaultContent()Метод переключает фокус назад на основную страницу или на первый фрейм на странице.
activeElement()Переключает фокус на активный элемент
alert()Переключает фокус на текущее активное модальное диалоговое окно в текущем экземпляре драйвера. Если такое окно не удалось найти, выбрасывается NoAlertPresentException.

Как интерфейс TargetLocator используется

Нужно создать экземпляр интерфейса WebDriver через создание нового объекта вызовом имплементирующего класса. После создания объекта работаем с интерфейсом:

TargetLocator
Интерфейс TargetLocator

Интерфейс Timeouts

В этом интерфейсе все методы для управления таймаутами в экземплярах WebDriver:

  • Имплицитное ожидание
  • Таймаут сценария
  • Таймаут загрузки страницы
WebDriver.Timeouts
Интерфейс WebDriver.Timeouts

Далее абстрактные методы, имплементируемые классом RemoteTimeouts, который является вложенным классом в классе RemoteWebDriver.

implicitlyWait(Duration duration)Ожидание указанный период времени на поиск элемента, указанного в параметре. Если не найден, эксепшен NoSuchElementException.
getImplicitlyWaitTimeout()Метод получает время, нужное WebDriver на поиск элемента.
scriptTimeout(Duration duration)Устанавливает время, нужное WebDriver на ожидание, пока асинхронный скрипт закончит выполнение, если нет, то выбрасывает эксепшен. Будет возвращен код ошибки с невалидным аргументом, если таймаут отрицательный или не null.
getScriptTimeout()Этот метод получает количество времени, которое WebDriver должен ожидать до завершения выполнения скрипта, затем выбрасывает ошибку.
pageLoadTimeout(Duration duration)WebDriver ожидает указанное в параметре количество времени, затем эксепшен
getPageLoadTimeout()Получает время, которое WebDriver должен ждать пока страница завершит загрузку

Использование: как и во всех предыдущих.

Timeouts
Интерфейс Timeouts

Как видим, следующие методы уже не поддерживаются:

  • implicitlyWait(long time, TimeUnit unit)
  • setScriptTimeout(long time, TimeUnit unit)
  • pageLoadTimeout(long time, TimeUnit unit)
  • setScriptTimeout()

Интерфейс JavaScriptExecutor

Для выполнения сниппетов на JS. Есть два абстрактных метода:

executeScript(String script, Object… args)Выполняет скрипт, указанный в параметре, в контексте текущего выбранного фрейма или окна
executeAsyncScript(String script, Object… args)Выполняет асинхронный скрипт, указанный в параметре, в контексте текущего выбранного фрейма или окна

Интерфейс TakesScreenshot

Снимает скриншоты страницы или WebElement-а и сохраняет, возвращая в эндпойнт в формате Base64.

Есть абстрактный метод:

getScreenshotAs(OutputType target)Снимает скриншот, всей страницы или веб-элемента, и сохраняет в указанное место. 

Интерфейс HasVirtualAuthenticator

Доступ к API виртуального аутентификатора (пользовательские пары имя-пароль с открытым ключом, хранимые на девайсе или в софт-хранилище). Аутентификаторы предназначены для аутентификации без паролей на основе ключей. Виртуальный аутентификатор эмулирует такие аутентификаторы для тестирования. Есть следующие абстрактные методы:

addVirtualAuthenticator​(VirtualAuthenticatorOptions options)Добавляет виртуальный аутентификатор, с опциями в параметре
removeVirtualAuthenticator​(VirtualAuthenticator authenticator)Удаляет его

Интерфейс PrintsPage

Вывод на печать текущей страницы в браузере. Абстрактные методы:

print​(PrintOptions printOptions)Опции в параметре. Чтобы иметь возможность печатать, нужно запустить Chromium в headless-режиме. При любой ошибке выбрасывается WebDriverException.

Интерфейс HasCapabilities

Интерфейс для рантайм-поиска функций по классам, с указанными свойствами. 

getCapabilities()Метод возвращает свойства текущего драйвера.

На этом описание интерфейсов WebDriver завершено. Переходим к WebElements и их иерархии.

Иерархия WebElement

Знание этой иерархии также необходимо; нельзя например запустить автотесты, пока не найдем WebElements на странице, чтобы выполнить с ними нужные действия.

WebElement — это интерфейс, расширяющий интерфейсы SearchContext и TakesScreenshot

Класс RemoteWebElement — полностью имплементированный класс интерфейса WebElement.

WebElement
Иерархия WebElement

Абстрактные методы, объявляемые в интерфейсе WebElement

Как видим на UML-диаграмме ниже, объявляются абстрактные методы, имплементируемые классами RemoteWebElement и EventFiringWebElement:

WebElement - абстрактные методы
Абстрактные методы в интерфейсе WebElement
click()Клик на текущем элементе. Для этого должны быть следующие предусловия:
— Элемент должен быть видимым
— Должен иметь высоту и ширину больше 0
Если элемент более не существует, будет эксепшенStaleElementReferenceException.
submit()Метод для работы с формами. Передает форму на удаленный сервер. Если элемента в форме нет, будет эксепшен StaleElementReferenceException. Внимание: в Selenium 4 это уже не имплементировано в отдельном эндпойнте, и работает через выполнение скрипта. Как пишут в документации Selenium, рекомендуется не применять этот метод, а лучше кликать кнопку Submit, чтобы отправить форму.
sendKeys(CharSequence… KeystoSend)Метод симулирует ввод текста в WebElement. Элемент должен быть с изменяемым атрибутом, или вводом в форму текстового типа. Если элемент не изменяемый, выбросится InvalidElementStateException. Если параметр KeystoSend равен null, метод выбросит IllegalArgumentException.
clear()Метод сбрасывает контент веб-элемента; для этого WebElement должен быть редактируемым и сбрасываемым; если нет, будет InvalidElementStateException.
getTagName()Возвращает имя тега веб-элемента. Например, из <input name=”foo” /> метод вернет “input”.
getDomProperty(String name)Метод получения значения текущего свойства элемента. Возвращает текущее свойство, даже если оно было изменено после загрузки страницы. Если свойство не задано, вернет null.
getDomAttribute(String name)Возвращает значение указанного атрибута. Если значения нет, null.
getAttribute()Возвращает значение атрибута с указанным именем. Если значения нет, null.
getAriaRole()Возвращает результат вычисления роли WAI-ARIA элемента. ARIA-роли могут описывать элементы, которые не существуют нативно в HTML или еще не имеют официально реализованной поддержки. 
getAccessibleName()Метод возвращает доступное имя и описание для Accessible Name элемента.
isSelected()Возвращает булево значение true/false, выбран ли текущий элемент. Это относится к input-элементам типа чекбоксов, выбираемых опций и радиокнопок. 
isEnabled()Возвращает булево значение, включен ли текущий элемент.
isDisplayed()Отображается ли.
getText()Передает видимый текст элемента, включая суб-элементы.
findElements(By by)Метод ищет все элементы в текущем контексте и возвращает список веб-элементов, с которыми далее работают исходя из стратегии в параметре метода. На этот метод влияет имплицитное ожидание во время выполнения. Метод возвращает соответствующие веб-элементы, как только найдет хотя бы один. Если время закончилось и ни одного не найдено, возвращается пустой список.
findElement(By by)Поиск элемента в текущем контексте и возвращение списка веб-элементов (как выше). Применяется имплицитное ожидание. Если не найден(ы), выбрасывается NoSuchElementException
getShadowRoot()Метод возвращает представление Shadow root элемента для работы с Shadow DOM веб-компонента. Если Shadow root не найден, выбрасывается NoSuchShadowRootException.
getLocation()Возвращает точку-локацию верхнего левого угла элемента.
getSize()Возвращает ширину и высоту отрендерённого элемента страницы.
getRect()Местоположение и размер элемента
getCssValue(String propertyName)Метод возвращает значение CSS-свойства; значения цветов в rgba- или rgb-строках. Например, если фоновый цвет элемента зеленый, метод вернет rgba(0, 255, 0, 1) или rgb(0,255,0).

Кратко

  • Класс RemoteWebDriver — полностью имплементированный класс интерфейса WebDriver.
  • Класс RemoteWebDriver имплементирует следующие интерфейсы:
    • WebDriver
    • JavaScriptExecutor
    • HasCapabilities
    • HasVirtualAuthenticator
    • Interactive
    • PrintsPage
    • TakesScreenshot
  • Каждый класс BrowserDriver (ChromeDriver, FirefoxDriver, etc.) расширяет класс RemoteWebDriver.
  • В классе RemoteWebDriver есть следующие вложенные классы:
    • RemoteTargetLocator
    • RemoteWebDriverOptions
  • Класс RemoteTargetLocator является вложенным в классе RemoteWebDriver, который имплементирует интерфейс WebDriver.TargetLocator.
  • RemoteWebDriverOptions является вложенным классом в классе RemoteWebDriver, имплементирует интерфейс WebDriverOptions, и имеет следующие вложенные классы:
    • RemoteTimeout – имплементирует интерфейс WebDriver.Timeouts.
    • RemoteWindow – имплементирует интерфейс WebDriver.Window.
  • Интерфейс WebDriver расширяет интерфейс SearchContext.
  • В интерфейсе WebDriver есть следующие вложенные интерфейсы:
    • Options
    • Window
    • Timeouts
    • Navigation
    • TargetLocator
  • Интерфейс WebElement имплементирует интерфейсы SearchContext и TakeScreenshot.
  • Классы RemoteWebElement и EventFiringWebElement classes являются полностью имплементированными классами интерфейса WebElement.

***

FAQ

Что такое иерархия Selenium?

Selenium — набор инструментов для автоматизации веб-браузеров. Иерархия Selenium — организация различных компонентов набора Selenium и их взаимодействия.

Какой супер-интерфейс в WebDriver?

Интерфейс SearchContext является супер-интерфейсом в Selenium WebDriver. 

WebDriver является главным интерфейсом в Selenium, он описывает набор методов управления браузером. SearchContext это интерфейс, который расширяется WebDriver’ом; в нем описываются методы поиска элементов страницы.

***

Источники: 1,2

Дополнительно:

 Ошибки в Selenium — гайд по exceptions

О чем спрашивают на собеседовании QA Junior по Selenium

Все остальное — на канале Automation QA | IT

Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

? Популярное

? Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас