t.me/atinfo_chat Telegram группа по автоматизации тестирования

HTML Elements - матчеры и ожидания

Добрый день коллеги, после первых успешно описанных страниц с помощью HTML Elements, столкнулся с другими проблемами.

  1. Ожидания, раньше они вызывались прямо по ходе теста в классическом виде

    new WebDriverWait(driver, 30).until(ExpectedConditions.elementToBeClickable((By.id(“accept-rules”))));
    Однако сейчас, они стали валиться с Null Pointer.
    Возникла так же и другая проблема, на странице появились два Select (описаны и задекорированы через ru.yandex.qatools.htmlelements.element.Select)
    Собственно, при выборе какого то пункта в первом Select - некоторое время происходит, подгрузка даннных во второй, элемент при этому остается кликабельными и видимым, как можно корректно дождаться подгрузки данных?

  2. Вопрос. Можно ли как то использовать матчеры для настройки ожиданий. Или матчеры это строго более гибкие проверки. Вопрос возник после прочтения вот этих Release Notes
    https://github.com/yandex-qatools/htmlelements/blob/master/releasenotes/1.10-releasenotes.ru.md#matchers-decoration

Поясню суть проблемы. Описал примерно форму, которая есть на нескольких экранах для разных ролей пользователей.
public class Planner extends HtmlElement {

@FindBy(id = “Going_To”)
public Select destination;

@FindBy(id = “Island”)
public Select subRegion;

public void fillForm(String dest, String sub, ) {
destination.selectByVisibleText(dest);
subRegion.selectByVisibleText(sub);

Потом вызываю этот метод в классе страницы

public class TaHomePage {
    private WebDriver driver;

    @FindBy(id = "vacation-planner-ta")
    private MainVacationPlanner mainVacationPlanner;

    public HomePage(WebDriver driver) {
        PageFactory.initElements(new HtmlElementDecorator(driver), this);
        this.driver = driver;
    }

    public void mimimalFillForm(String dest, String sub, )  {
        this.mainVacationPlanner.fillForm(dest, sub);

    }

}

и в тесте

public void id01testCase1Hold(String destination, String subRegion) {

taHomePAge.mimimalFillForm(destination, subRegion);

Проблема в том, что данные в Select subRegion подгружаются, через некоторое время после выбора destination.selectByVisibleText(dest);
Если вызывать wait в классе формы - то летит Null Pointer, driver = null, а нарушать структуру и выделять выбор селектов как два отдельных метода, что бы вызывать wait в классе страница - не хочется. Может кто нибудь поделится своими соображениями на этот счет.

А откуда вы берете driver внутри блока HtmlElement?
Можно сделать что-то типа такого:

    public class Planner extends HtmlElement {  
  
    private WebDriver driver;

    public void setDriver(WebDriver driver){
         this.driver = driver;
    }
    public WebDriver getDriver(){
         return driver;
    }

    @FindBy(id = "Going_To")
    public Select destination;
            
    @FindBy(id = "Island")
    public Select subRegion;
            
    public void fillForm(String dest, String sub, ) {
         destination.selectByVisibleText(dest);
         subRegion.selectByVisibleText(sub);
    }

В из пейджа передать двайвер в блок

public class TaHomePage {
    private WebDriver driver;

    @FindBy(id = "vacation-planner-ta")
    private MainVacationPlanner mainVacationPlanner;

    public HomePage(WebDriver driver) {
        PageFactory.initElements(new HtmlElementDecorator(driver), this);
        this.driver = driver;
        mainVacationPlanner.setDriver(this.driver);
    }

    public void mimimalFillForm(String dest, String sub, )  {
        this.mainVacationPlanner.fillForm(dest, sub);           
    }
}

и в блоке использовать его, для реализации ожидалок.

Либо использовать матчеры. Как это сделать можно почитать здесь https://github.com/yandex-qatools/matchers-java/tree/master/matcher-decorators

Ага спасибо попробую. Просмотрел матчеры - не увидел, если что то навроде подождать пока в Selecte (ru.yandex.qatools.htmlelements.element.Select;) появится option с каким то value

Просмотрел сырцы для матчеров - все таки маловато у меня скилов. Коллеги, можете подсказать аналоги для

new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(By.id("interstitial_page")));

и

new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.id("Island")));
  1. добавить отрицание в матчер:

    assertThat(element, should(not(exists())).whileWaitingUntil(timeoutHasExpired(SECONDS.toMillis(5))));

  2. Описание из javadocs
    elementToBeClickable(By locator) - An expectation for checking an element is visible and enabled such that you can click it.
    А в сорцах https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/support/ui/ExpectedConditions.java .
    Видно что, elementToBeClickable проверяет элемент на visible и на enabled.
    Матчеры для проверки visible и enabled - тут https://github.com/yandex-qatools/matchers-java/tree/master/webdriver-matchers
    Конкретнее:
    displayed() - значение свойства element.isDisplayed() положительно
    enabled() - значение свойства element.isEnabled() положительно

2 Симпатий

Спасибо огромное.

Для “спасибо” есть кнопочка специальная. Уже не первый раз наблюдаю в ваших темах. :wink:

2 Симпатий

Будем надеяться, что кнопочка спасибо == нравится.

Хотя теперь снова не понимаю. Если честно не до конца понимаю вот эту строку

SECONDS.toMillis(5)

У меня где то должно быть такое поле или константа? Если я просто пробую передавать int компилятор ругается на не совместимость типов.

То есть как я понял матчер задекорированный ожиданием isEnabled выглядит так

@FindBy(id = "Island")
public Select subRegion;

assertThat(subRegion, should(isEnabled()).whileWaitingUntil(timeoutHasExpired()));

Попробуйте

import java.util.concurrent.TimeUnit;

TimeUnit.SECONDS.toMillis(5)
assertThat(subRegion, should(isEnabled()).whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(20))));

при такой реализации - компилятор предлагает создать метод assertThat, хотя импорт

import static org.hamcrest.MatcherAssert.assertThat;

есть

Хотя…IDEA подсвечивает или имя метода или его сигнатуру…ничего не понимаю…

Но когда подсвечивается сигнатура, импорт идет из

import static org.hamcrest.MatcherAssert.assertThat;

Подсвечивает - это компилятор ругается?
Обычно это сопровождается каким-то сообщением. Хотелось бы увидеть его.

На вскидку могу предположить, что у Вас несколько импортов метода assertThat.
Или же, если ассерты внутри класса наследника HtmlElement, то метод isEnabled() берется именно из него, а не из WrapsElementMatchers или WebElementMatchers. Тогда нужно явно указать откуда брать метод isEnabled()

Сорри. Разобрался делал импорт матчеров для WebElement, а не для Wrapers

Возникла вот такая вот проблема
Есть метод:

public void login(String industry, String email, String password) throws IOException{
    emailInput.clear();
    emailInput.sendKeys(email);
    passwordInput.sendKeys(password);
    getStartedButton.click();
}

Используется он вот так вот

public HomePage loginAs(Agent agent) throws IOException{
    login(agent.getEmail(),agent.getPassword());
    assertThat(advancedSearch, should(isEnabled()).whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(60))));
    assertThat(advancedSearch, should(isDisplayed()).whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(60))));
    return new TaHomePage(driver);

Эти два ассерта должны проверить, что после нажатия на кнопку загрузилась страница с нужной нам кнопкой

@FindBy(css = "a.adv_search")
private Button advancedSearch;

Но вот, что выводится в консоли

Listening on port 36107
org.openqa.selenium.NoSuchElementException: Timed out after 5 seconds. Unable to locate the element
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '2.43.0', revision: 'accb3003b9fb8f7cae30f9669b4c594a065396a6', time: '2014-09-09 22:22:51'
System info: host: 'ASHIPOVALOV', ip: '172.31.42.69', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.8.0_31'
Driver info: driver.version: unknown
	at ru.yandex.qatools.htmlelements.pagefactory.AjaxElementLocator.findElement(AjaxElementLocator.java:73)
	at ru.yandex.qatools.htmlelements.loader.decorator.proxyhandlers.WebElementNamedProxyHandler.invoke(WebElementNamedProxyHandler.java:29)
	at com.sun.proxy.$Proxy12.isEnabled(Unknown Source)
	at ru.yandex.qatools.htmlelements.matchers.common.IsElementEnabledMatcher.matchesSafely(IsElementEnabledMatcher.java:18)
	at ru.yandex.qatools.htmlelements.matchers.common.IsElementEnabledMatcher.matchesSafely(IsElementEnabledMatcher.java:15)
	at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
	at ru.yandex.qatools.htmlelements.matchers.common.WrapsElementMatcher.matchesSafely(WrapsElementMatcher.java:25)
	at ru.yandex.qatools.htmlelements.matchers.common.WrapsElementMatcher.matchesSafely(WrapsElementMatcher.java:16)
	at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
	at ru.yandex.qatools.htmlelements.matchers.decorators.WaiterMatcherDecorator.matchesSafely(WaiterMatcherDecorator.java:26)
	at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
	at ru.yandex.qatools.htmlelements.matchers.decorators.MatcherDecoratorsBuilder.matchesSafely(MatcherDecoratorsBuilder.java:30)
	at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)

То есть получается ассерты не отрабатывают - потому, что они относятся к элементу другой страницы? Но как тогда можно подождать точной и полной загрузки другой страницы.

Вообще говоря, ассерты не должны быть частью страниц. Так что начать следует с их вынесения непосредственно в тесты.

Тогда не до конца ясно, как реализовать ожидания используя HTML Elements. Да и вообще разве использование WebElemenet в тестах, не противоречит принципам PageObject?