- История Selenium
- Иерархия WebDriver
- Интерфейсы в WebDriver
- Иерархия WebElement
- Абстрактные элементы
- FAQ
Кратко о Selenium и его создателях
С начала Нулевых, с активным внедрением JavaScript, у QA-инженеров возникла потребность в отдельном приложении для тестирования кода на JS. Поэтому Джейсон Хаггинс, уже тогда видный деятель QA-комьюнити, создал в 2004 году — нет, еще не Selenium — а только JavaScriptTestRunner.
Наверное, эта выдающаяся личность требует отдельного упоминания.
Как характеризуют его в глобальном комьюнити, «невероятно мудр, колоссально опытен, у него бывают гениальные озарения, и он очень упрям». Сейчас он делает роботов для тестирования тачскринов — 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 4 WebDriver полностью совместим с требованиями W3C по браузерам. Уже с 2020 года не нужны специальные «твики» в Selenium-сценариях, чтобы они работали во всех браузерах, потому что все работает «по стандартному протоколу» W3C. Поэтому есть смысл полностью переходить на 4-ю версию Selenium.
Начиная с версии 4.6.0 [последняя версия — 4.10], Selenium Manager управляет всеми нужными браузер-драйверами, без внешних библиотек типа WebDriverManager; на машину ставится соответствующий драйвер, и выполняются тесты.
Итак, этой строчкой кода мы запускаем Chrome:
WebDriver driver = new ChromeDriver();
И получаем доступ ко всем методам. Теперь посмотрим на иерархию WebDriver:
Класс RemoteWebDriver
Начнем с класса RemoteWebDriver
— это полностью имплементированный класс интерфейса, расширяемый каждый классом BrowserDriver
в Selenium-фреймворке.
В классе RemoteWebDriver
имеются следующие вложенные (nested) классы:
- RemoteTargetLocator — полностью имплементированный класс интерфейса
WebDriver.TargetLocator
.
- RemoteWebDriverOptions — полностью имплементированный класс интерфейса
WebDriver.Options
. В этом классе есть вложенные:
- RemoteTimeouts — этот класс имплементирует интерфейс
WebDriver.Timeouts
, с полной имплементацией всех его абстрактных методов:
- RemoteWindow — имплементирует интерфейс
WebDriver.Window
с полной имплементацией всех его абстрактных методов.
Вложенные классы в RemoteWebDriver:
Как работать с классом RemoteWebDriver
Конструкторы для создания экземпляров класса:
- RemoteWebDriver(ICapabilities)
- RemoteWebDriver(Uri, ICapabilities)
- RemoteWebDriver(ICommandExecutor, ICapabilities)
- RemoteWebDriver(Uri, ICapabilities, TimeSpan)
Далее в примере используется RemoteWebDriver(Uri, ICapabilities)
для запуска тестов на популярной платформе LambdaTest. Реализация на другой платформе может отличаться в зависимости от конфигурации — но принципы работы с классомRemoteWebDriver
остаются теми же.
Класс RemoteWebDriver имплементирует такие интерфейсы:
- WebDriver
- JavaScriptExecutor
- TakesScreenshot
- HasVirtualAuthenticator
- PrintsPage
- HasCapabilities
- Interactive
Далее подробнее.
Интерфейс WebDriver
Это «ядро» WebDriver, ключевой интерфейс со всеми нужными методами; и вложенными интерфейсами. Все эти методы симулируют действия пользователя в браузере.
Ниже UML-диаграмма интерфейса WebDriver в Selenium WebDriver 4:
Далее перечислим абстрактные методы.
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-объекта.
Переходим ко вложенным (nested) интерфейсам.
Вложенные интерфейсы в WebDriver
Интерфейс Window
Через этот интерфейс идут операции с текущим окном.
В нем абстрактные методы, полностью имплементированные классом RemoteWebDriver
:
getSize() | Возвращает внешние размеры текущего окна |
setSize(Dimension dimension) | Текущие и внешние размеры окна. (Метод отвечает window.resizeTo() в JavaScript) |
getPosition() | Возвращает позицию текущего окна относительно верхнего левого угла экрана |
setPosition(Point targetPosition) | Передвигает окно (устанавливает его позицию) относительно левого верхнего угла экрана; соответствует window.moveTo() в JS |
maximize() | Максимизирует окно (если еще не развернуто) |
minimize() | Сворачивает окно в панель задач (если не свернуто) |
fullScreen() | Разворачивает окно на весь экран (если еще не) |
Применение: создается экземпляр интерфейса — созданием нового объекта через вызов имплементирующего класса. После создания объекта:
Интерфейс Options
Это доступ к меню браузера.
- Добавлять, получать, и удалять cookie
- Выставлять таймауты в браузере
- Управлять окном
- Выводить логи, разных типов
Список абстрактных методов, полностью имплементированных в классе 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
-интерфейс:
Интерфейс Navigation
Методы для истории в браузере и навигации по URL:
- Назад/Вперед в истории
- Перейти на указанный URL
- Обновить страницу
back() | Метод симулирует нажатие кнопки Назад в браузере |
forward() | Кнопки Вперед |
to(String url) | Переход по URL (в String-формате в параметре) |
to(URL url) | Перегруженный метод to(String url) , то же действие (в параметре в URL-формате) |
refresh() | Обновляет страницу |
Как и во всех предыдущих примерах, создается экземпляр интерфейса WebDriver
через создание нового объекта вызовом имплементирующего класса. После создания объекта:
Интерфейс TargetLocator
Методы отправки команд в фреймы и окна:
- Работа с окнами и табами браузера
- Фреймами
- А также Alerts в браузере
Абстрактные методы, имплементируемые классом 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
через создание нового объекта вызовом имплементирующего класса. После создания объекта работаем с интерфейсом:
Интерфейс Timeouts
В этом интерфейсе все методы для управления таймаутами в экземплярах WebDriver
:
- Имплицитное ожидание
- Таймаут сценария
- Таймаут загрузки страницы
Далее абстрактные методы, имплементируемые классом RemoteTimeouts
, который является вложенным классом в классе RemoteWebDriver
.
implicitlyWait(Duration duration) | Ожидание указанный период времени на поиск элемента, указанного в параметре. Если не найден, эксепшен NoSuchElementException . |
getImplicitlyWaitTimeout() | Метод получает время, нужное WebDriver на поиск элемента. |
scriptTimeout(Duration duration) | Устанавливает время, нужное WebDriver на ожидание, пока асинхронный скрипт закончит выполнение, если нет, то выбрасывает эксепшен. Будет возвращен код ошибки с невалидным аргументом, если таймаут отрицательный или не null . |
getScriptTimeout() | Этот метод получает количество времени, которое WebDriver должен ожидать до завершения выполнения скрипта, затем выбрасывает ошибку. |
pageLoadTimeout(Duration duration) | WebDriver ожидает указанное в параметре количество времени, затем эксепшен |
getPageLoadTimeout() | Получает время, которое WebDriver должен ждать пока страница завершит загрузку |
Использование: как и во всех предыдущих.
Как видим, следующие методы уже не поддерживаются:
- 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
Как видим на UML-диаграмме ниже, объявляются абстрактные методы, имплементируемые классами RemoteWebElement
и EventFiringWebElement
:
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’ом; в нем описываются методы поиска элементов страницы.
***
Дополнительно:
Ошибки в Selenium — гайд по exceptions