[Code Recipe] Cоздание кастомных локаторов для Selenium WebDriver на Java

В поддержку новой инициативы - мега склад примеров на github
Создаем примеры по автоматизации вместе, просто присылайте pull requrest
А также инициативы создания at.info code recipes

Вашему вниманию предлагается рецепт создания кастомных локаторов.

Казалось бы, зачем нужно создавать кастомные локаторы, если сей велосипед уже давно изобретен в качестве связки FindBy + WebElement, либо использования чистого By?

Начнем с простого. Лично я предпочитаю использовать класс By, ввиду гибкости его последующего применения. Но, скажу по правде, сама читабельность и громоздкость конструкций по типу:

private By element = By.id("elementID");

так и напрашивается на рефакторинг, в отличии от той же свзки FindBy + WebElement, где все предельно лаконично и понятно. Так вот, первой причиной кастомизации стало желание навести марафет классу By.

Допустим, мы преобразили наш локатор. Так почему бы теперь не использовать всю мощь его кастомизации исплементацией решения проблемы формирования элементов “на лету”? На самом деле проблемы то особой и нет, но лично мне режет глаза способ формирования локаторов внутри методов пейдж обджектов. Подобные no name элементы выпадают из общего контекста модели реальной страницы. Да, кто-то скажет, что в таком случае нужно опускаться до уровня PageElement, но имеет ли это смысл в случае стандартных, не кастомизированных контролов?

Экономия места. Допустим, у нас есть множество однотипных элементов без каких-либо уникальных атрибутов, к которым должен быть органзован быстрый доступ для любого рода взаимодействия, будь то getText или click. Мы можем создать десяток локаторов, отличающихся только индексом или текстом, либо вынести все это дело в отдельный метод, который будет использовать неименованый динамический локатор для дальнейшей передачи Selenium API. В первом случае наш пейдж обджект раздуется до неимоверных размеров, не говоря уже о том, что использование подобного рода хардкода индексов или текста - моветон, ввиду обречения себя на вечный рефакторинг после изменений в UI. Недостаток второго способа уже обсуждался выше.

Передача кастомных параметров. Собственно, сама идея кастомизации локаторов развязывает нам руки в ситуации, когда элементу нужно передать особые параметры. Чего не сделаешь при использовании стандартных аннотаций селениума, либо класса By.

Об еще одном интересном способе использования кастомных локаторов я расскажу в одном из следующих рецептов, а пока давайте смотреть код.

Пусть все наши элементы будут иметь кастомную аннотацию HTML:

Наведем теперь марафет классу By:

Собственно, сама обертка реализует метод updateElement, позволяющий формировать локаторы на лету. Как это будет выглядеть, увидим в реализации пейдж обджекта.

Теперь нам нужно как-то инициализировать наши кастомные локаторы. Сделать это можно при помощи рефлексии внутри нашей абстрактной страницы:

Причем, не имеет значения, какой была исходная страница. Данный механизм поддерживает вариант иерархического наследования, если нам нужно спуститься по цепочке по нескольким пейджам до их родителя. Реальное использование данного механизма будет освещено в одном из следующих рецептов.

Тестовая страница будет выглядеть следующим образом:

В идале тут их должно быть несколько, но в целях экономии времени все элементы были упакованы в один пейдж. Из приведенного примера видно использование касмтоных локаторов, как статических, так и динамических, которые помечаются спец. символом ? внутри пути. Данный символ будет заменен в рантайме недостающим звеном, необходимым для однозначной идентификации элемента на странице. Кое-где проскакивает хардкод, чисто в демонстративных целях.

Сам тест выглядит следующим образом (опять-таки без доп. обертки):

Следует также отметить механизм мягких ассертов, который будет активно применятся в следующих рецептах.

Полный код того, что было реализовано, можно найти здесь.

Пусть таких примеров станет больше, присылайте pull request на наш мега-склад примеров.

4 лайка