Прошло уже столько времени, столько воды утекло и все же где хранить локаторы в Page Object ?
Армия автоматизаторов разбилась на 3 лагеря.
Константы
@FindBy
Внешний файл
Вот мои размышления :
Если хранить веб елементы то их может и не быть на странице и значит что тест может упасть по причине не описанной в ТС.
Самый оптимальный
Удобно но для каждого класса плодить файлы тоже не хотелось
А как свои локаторы храните ВЫ ?
Update: Где вы храните временные элементы?
Припустим : Зайти на сайт, перейти в список товаров, запомнить первый товар, вернуться на главную, проверить есть ли этот товар на домашней странице.
Вопрос: Где хранить название товара?
Update: Где вы храните временные элементы?
Припустим : Зайти на сайт, перейти в список товаров, запомнить первый товар, вернуться на главную, проверить есть ли этот товар на домашней странице.
Вопрос: Где хранить название товара?
Ничего страшного, если в двух разных тестах будет прописан одинаковый локатор.
В случае смены локатора (класс у кнопки поменялся), можно сделать поиск/замену в IDE по всему проекту с тестами.
Представь, если у тебя Single Page Application, где кнопок может быть сотня.
Не все сразу видны на странице.
Например, на главной странице есть список категорий, внутри каждой своя форма, внутри формы куча кнопок.
Как ты назовёшь переменную в ObjectPage для такой вложенной кнопки?
При этом сам локатор короткий лаконичный.
Плюс надо подгружать PageObject со списком всех локаторов в каждый тест.
И ещё пример. Как быть, когда одна кнопка может иметь разные локаторы, в зависимости от каких-либо условий?
В тесте А ты авторизован пользователем и кнопка имеет класс user-button.
В тест Б ты авторизован админом и эта же кнопка имеет класс admin-button.
Как быть с PageObject в таком случае?
В решении, которое я предлагаю, об этом думать не нужно.
В одном тесте используем статичный локатор с одним классом, а в другом тесте с другим.
Нет?
Если у вас локатор повторяется хотя бы два раза в одном классе, то его можно вынести по принципу private By buttonLocator = By.cssSelector("cssSelector");
Если у вас Angular приложение, то вы можете создавать Пейдж Классы под каждую страницу, даже если урл при этом не меняется. И даже если у вас не сингл пейдж приложение, то в пределах одной страница вы можете создавать отдельный классы для компонентов на странице. Кто вам сказал что Одна страница = Один Пейдж Класс?
Подгружать все локаторы каждый тест не надо. Вы знаете что такое ленивая инициализация?
Если одна и та же кнопка имеет разные локаторы при разных условиях, то да вам необходимо держать два локатора.
Вы очень уверенно рассказываете как должно быть, основываясь только лишь на своем понимании.
Не вижу тэга какого-то конкретного инструментария (кроме webdriver), поэтому спрошу - а как с этим обстоит дело в codeception? Есть ли там аналог аннотаций @FindBy? Как в целом codeception предлагает оптимально в своих рамках хранить локаторы и работать с ними? @davert, расскажите, как codeception позиционирует себя в этом ключе?)
ИМХО 3-й способ - наиболее оптимален, поскольку позволяет не перекомпиливать тесты в случае изменения локаторов, а решать вопрос изменением ресурсного файла.
Я упоролся по ленивым элементам - пока нет обращения к элементу - поиск на странице не происходит. То же самое при вылетающем StaleReferenceException или NoSuchElementException - нужно просто попытатся переискать элемент, и только потом падать. Брат жив зависимость есть. Код намного проще.
Такой подход используется в ProtractorJS, Selenide, и куче других.
1 - константы - не спасают от необходимости искать элемент только в нужное время, да и хранить локаторы\стринги - не так удобно как элементы
2 - ФайндБай - полный мрак и ужас. Монструозные абстракции просто для того чтобы обьявить элемент? Плюс проблемы когда хочешь возвращать свои типизированные элементы. Плюс проблемы когда хочешь искать от элемента к элементу. Не мой выбор.
3 - Внешний файл точно не вариант - очень замедляет разработку и рефакторинг - приходится свичится между файлами туда сюда что очень утомляет. Да и всеравно сам по себе не решение - так же приходится в классе использовать пейдж фактори или константы. Не мой выбор
Да я тоже понял что оптимальней всего хранить всё в “By”, но сейчас пошли еще дальше, написаны обьекты типа Button, Label, CheckBox, etc… в которые передаются By.
В итоге переменная выглядит как
private static final InputBox NAME_FIELD = controlFactory().inputBox(By.id("createGroupName"));
Храню тупо в ямле, а распределением локаторов по классам страниц занимается базовый класс (PageObject). Когда страница наследуется от base_page, она забирает свою часть локаторов. Ну и конечно это все xpath и держать некоторые длинные пути в коде - не кошерно.