В этой версии упор был сделан, в основном, на исправление недочетов, которые были обнаружены нашим сообществом.
Мы поправили несколько недочетов архитектуры и пару ошибок, связанных с инициализацией List<Т extends HtmlElements>
.
Также у нас появились контрибьюторы! Огромное спасибо @lanwen за отличную реализацию идей "WaitFor" и "Refresh" матчеров. И, хотя один pull-реквест у нас еще не принят, авансом спасибо @pazone за идею матчера для рекурсивной проверки наличия на странице внутренних элементов блока. Надеемся, что он появится в следующей версии.
Если ты, дорогой читатель, еще не получил свое "спасибо" от команды Yandex QATools, то присылай свои идеи и реализации нам!
А теперь о новом подробнее.
Это одно из основных и очень важных нововведений. Теперь по умолчанию при инициализации элементов вместо
DefaultElementLocator
будет использоваться AjaxElementLocator
. Это позволяет производить поиск элементов при обращении
к ним не сразу же, а с задержкой (по умолчанию в 5 секунд). Из названия Ajax...
понятно, для чего это нужно.
Мы также добавили возможность использовать свою реализацию ElementLocator
вместо нашей при инициализации элементов
и page-объектов:
HtmlElementLoader.populateHtmlElement(HtmlElement htmlElement, CustomElementLocatorFactory locatorFactory)
HtmlElementLoader.populatePageObject(Object page, CustomElementLocatorFactory locatorFactory)
С ростом количества JavaScript логики на клиентской стороне, в тестах все чаще требуется использовать различные таймауты.
Пусть, к примеру, нам потребовалось проверить, что на главной странице Яндекса после вводе запроса
в поисковую строку появляется саджест. Но саджест подгружается асинхронно, поэтому проверку нужно проводить по истечении
некоторого времени.
Чтобы проводить подобные проверки было просто и удобно, мы реализовали "WaitFor" матчер. С его помощью можно
декорировать другие матчеры и выполнять проверки по истечении таймаута. Вот пример использования этого матчера:
MainPage mainPage = new MainPage(driver);
mainPage.getSearchArrow().getRequestInput().sendKeys(REQUEST);
assertThat(mainPage.getSuggest(), withWaitFor(exists()));
В этом случае матчер exists()
будет выполняться каждые 500 мс (интервал по умолчанию).
Если в течении в течении 30000 мс (время ожидания по умолчанию) exist() хотя бы раз возвратит true, то и вся проверка пройдет
успешно. В противном случае вы увидите красивое сообщение об ошибке:
Expected: While waiting [<30000L>] millis it should be: element existing on page
but: element Suggest not existing on page
Также, при необходимости можно переопределить время ожидания:
int timeoutInMilliseconds = 10000; //10 секунд
MainPage mainPage = new MainPage(driver);
mainPage.getSearchArrow().getRequestInput().sendKeys(REQUEST);
assertThat(mainPage.getSuggest(), withWaitFor(exists(), timeoutInMilliseconds));
Или время ожидания вместе с интервалом выполнения проверки:
int timeoutInMilliseconds = 10000; //10 секунд
int intervalInMilliseconds = 50; //50 милисекунд
MainPage mainPage = new MainPage(driver);
mainPage.getSearchArrow().getRequestInput().sendKeys(REQUEST);
assertThat(mainPage.getSuggest(), withWaitFor(exists(), timeoutInMilliseconds, intervalInMilliseconds));
Вот такой прелестный матчер.
Иногда в тестах требуется сделать какую-нибудь проверку после обновления страницы. Например, это необходимо, если
запрос отправляется на сервер асинхронно, а результат его выполнения виден только после перезагрузки страницы.
Или же, например, если нужно проверить, что какой-то элемент страницы изменяется при каждом ее обновлении (это может быть
рекламный баннер, капча, или пример поискового запроса на главной странице Яндекса).
"Refresh" матчер позволяет делать такие проверки очень компактно и удобно. Он декорирует любой другой матчер,
принимая дополнительно на вход экземпляр класса WebDriver, и перед выполнением проверки обновляет открытую в нем страницу.
К примеру, проверим, что пример поискового запроса на главной странице Яндекса изменяется
при обновлении страницы:
MainPage mainPage = new MainPage(driver);
String currentText = mainPage.getSearchSample().getText();
assertThat(mainPage.getSearchSample(), withPrerefresh(not(hasText(currentText)), driver));
В этом случае проверка not(hasText(...))
будет выполнена только после перезагрузки страницы. В случае ошибки вы увидите
исчерпывающее сообщение:
Expected: (after refresh) not element with text: церемония "Грэмми"
but: was <element with text: церемония "Грэмми">
Так же, этот матчер очень удобно использовать вместе с матчером "WaitFor". Пусть, например, нам нужно проверить, что в почтовый ящик в течении некоторого времени придет письмо с определенной темой. Эту проверку можно сделать очень просто и изящно:
assertThat(mailPage.getMailsList(), withWaitFor(withPrerefresh(hasMailWithSubject(SUBJECT), driver)));
В этом случае будет проведено множество попыток найти письмо в списке, до тех пор пока оно не найдется или не истечет таймаут. При этом каждая новая проверка будет начинаться с перезагрузки страницы.
В предыдущей версии при инициализации cписка HtmlElement-ов (или TypifiedElement-ов) происходило сравнение каждого
элемента коллекции с каждым из-за неудачного способа именования элементов списка. В результате работа с со списками
существенно притормаживала.
В этой версии мы исправили алгоритм именования элементов списка, и теперь все работает отлично.
Методы isDisplayed()
, isEnabled()
, isSelected()
, как оказалось, жизненно необходимы при работе с любыми элементами.
Поэтому мы добавили эти методы в базовый класс TypifiedElement.
Концепция типизированных элементов пока еще сыровата, на нее мы сделаем упор в следующей версии.
В прошлой версии при реализации Checkbox'а бы допущена архитектурная ошибка:
public void select() {
if (!getWrappedElement().isSelected()) {
getWrappedElement().click();
}
}
public void deselect() {
if (getWrappedElement().isSelected()) {
getWrappedElement().click();
}
}
public boolean isSelected() {
return getWrappedElement().isSelected();
}
В таком контексте, при необходимости переопределить метод isSelected()
приходилось переопределять и остальные методы.
Это было не удобно, и поэтому мы изменили реализацию методов select()
и deselect()
:
public void select() {
if (!isSelected()) {
getWrappedElement().click();
}
}
Мы сделали отдельный модуль, который включает в себя htmlelemnts-java и htmlelements-matchers последней версии. Это позволяет использовать вместо двух зависимостей одну:
<dependency>
<groupId>ru.yandex.qatools.htmlelements</groupId>
<artifactId>htmlelements-all</artifactId>
<version>1.9</version>
<dependency>
При необходимости вы, как и раньше, можете использовать модули htmlelemnts-java и htmlelements-matchers по отдельности.
Версия селениума обновлена до 2.29.0
Предыдущая версия была собрана под Java 1.7. Однако Java 1.6 по прежнему используется очень широко. Чтобы у пользователей, использующих Java 1.6, не возникало конфликтов при подключении Html Elements к своему проекту, мы собрали новую версию под Java 1.6.
В версии 1.9 пока все, но продолжение следует! А сейчас пора бежать спасать мир :)