Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

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


(Александр Шиповалов) #1

Добрый день коллеги, после первых успешно описанных страниц с помощью 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


Проблемы с инициализацией блоков в HtmlElements
(Александр Шиповалов) #2

Поясню суть проблемы. Описал примерно форму, которая есть на нескольких экранах для разных ролей пользователей.
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 в классе страница - не хочется. Может кто нибудь поделится своими соображениями на этот счет.


(Владимир Фролов) #3

А откуда вы берете 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


(Александр Шиповалов) #4

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


(Александр Шиповалов) #5

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

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

и

new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.id("Island")));

(Владимир Фролов) #6
  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() положительно


(Александр Шиповалов) #7

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


(Sergey Korol) #8

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


(Александр Шиповалов) #9

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


(Александр Шиповалов) #10

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

SECONDS.toMillis(5)

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


(Александр Шиповалов) #11

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

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

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

(Владимир Фролов) #12

Попробуйте

import java.util.concurrent.TimeUnit;

TimeUnit.SECONDS.toMillis(5)

(Александр Шиповалов) #13
assertThat(subRegion, should(isEnabled()).whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(20))));

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

import static org.hamcrest.MatcherAssert.assertThat;

есть


(Александр Шиповалов) #14

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


(Александр Шиповалов) #15

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

import static org.hamcrest.MatcherAssert.assertThat;

(Владимир Фролов) #16

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

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


(Александр Шиповалов) #17

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


(Александр Шиповалов) #18

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

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)

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


(Sergey Korol) #19

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


(Александр Шиповалов) #20

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