@FindBy WebElements не инициализируются в структуре PageFactory/Page Object

Обновленный код:

public class FlightBookingTest extends PageBase{

@Test(priority = 1)
@Parameters({"from", "to"})
public void searchForAPackage(String from, String to) throws InterruptedException {

    customerHomePage().selectDepartureAirport(from);
    customerHomePage().selectDestinationAirport(to);
    customerHomePage().selectStartDate();
    customerHomePage().submitSearchRequest();

    assertThat(searchResultsPage().checkPageTitle(), equalTo("Flight Results"));
}

Объект страницы:

public class CustomerHomePage extends PageBase {

@FindBy(how = How.XPATH, using = ".//* [@id='container']/div/div[3]/div/div[1]/div/h3")
public WebElement searchResults;  
//loads more locators

public CustomerHomePage(WebDriver driver) {
    this.driver = driver;
    driver.manage().window().maximize();
}

public void visit(String url){
    driver.get(baseURL);
}

public void selectDepartureAirport(String departureAirport) {
    click(whereFromDropdown);
    selectOption(departureAirport);
}

public void selectDestinationAirport(String destination) {
    click(destinationLocator);
    type(destination, destinationLocator);
    selectOption("(" + destination + ")");
}

public void selectFromDate() {
    type("15/07/2016", dateFromField);
}

public void submitSearchRequest() {
    click(submitSearchButton);
    waitForIsDisplayed(searchResults, 120);
}

public void selectStartDate() {
    click(dateFromField);
    click(nextMonthSelector);
    click(dayOfMonth);
}

База страниц:

public class PageBase extends  TestBase {

public CustomerHomePage customerHomePage()
{
    return PageFactory.initElements(driver, CustomerHomePage.class);
}

Тестовая база:

public class TestBase implements Config {

public WebDriver driver;
//a bunch of methods to handle Driver instantiation and kill

//a bunch of Webdriver utility methods including:
public void click(WebElement element) {
    waitForIsDisplayed(element, 120);
    element.click();
}
 public Boolean waitForIsDisplayed(WebElement element, Integer... timeout) {
    try {
        waitFor(ExpectedConditions.visibilityOf(element),
                (timeout.length > 0 ? timeout[0] : null));
    } catch (org.openqa.selenium.TimeoutException exception) {
        return false;
    }
    return true;
}

private void waitFor(ExpectedCondition<WebElement> condition, Integer timeout) {
    timeout = timeout != null ? timeout : 5;
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    wait.until(condition); //java.lang.reflect.UndeclaredThrowableException HERE...Caused by NoSuchElementException
}

Похоже, фреймворк не соблюдает ожидание ожидаемых условий - видимость элемента. Я подозреваю, что это связано с реализацией 'visibilityOf(element)' и с тем, как @FindBy инициализирует элементы.

Трассировка стека исключения:

java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy7.findElement(Unknown Source)
at org.openqa.selenium.support.pagefactory.DefaultElementLocator.findElement(DefaultElementLocator.java:69)
at org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler.invoke(LocatingElementHandler.java:38)
at com.sun.proxy.$Proxy9.isDisplayed(Unknown Source)
at org.openqa.selenium.support.ui.ExpectedConditions.elementIfVisible(ExpectedConditions.java:302)
at org.openqa.selenium.support.ui.ExpectedConditions.access$100(ExpectedConditions.java:41)
at org.openqa.selenium.support.ui.ExpectedConditions$10.apply(ExpectedConditions.java:288)
at org.openqa.selenium.support.ui.ExpectedConditions$10.apply(ExpectedConditions.java:285)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:238)
at com.multicom.fabrix.framework.TestBase.waitFor(TestBase.java:152)
at com.multicom.fabrix.framework.TestBase.waitForIsDisplayed(TestBase.java:141)
at com.multicom.fabrix.pageobjects.CustomerHomePage.waitForResults(CustomerHomePage.java:75)
at com.multicom.fabrix.regressiontests.FlightBookingTest.searchForAPackage(FlightBookingTest.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:643)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:74)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.mycompany.mymodule.webdriver.WebDriverInvoker.invokeNormally(WebDriverInvoker.java:47)
at com.mycompany.mymodule.webdriver.WebDriverInvoker.invoke(WebDriverInvoker.java:38)
... 41 more

Вызвано: org.openqa.selenium.NoSuchElementException: такого элемента нет: невозможно найти элемент: {"method":"xpath","selector":".//*[@id='container']/div/div [3]/дел/дел[1]/дел/h3"}


person Steerpike    schedule 30.08.2016    source источник


Ответы (2)


Переключите свой класс PageBase на ниже. Ранее вы инициализировали прокси, но не возвращали этот экземпляр, а просто новый объект. В противном случае вы можете вставить строку initElements в конструктор CustomerHomePage, используя 'this' вместо 'CustomerHomePage.class'

public class PageBase extends SeleniumBase {

public CustomerHomePage customerHomePage()
{
    return PageFactory.initElements(driver, CustomerHomePage.class);
}
person Grasshopper    schedule 30.08.2016
comment
Спасибо. Работает как объяснил - person Steerpike; 30.08.2016
comment
чего я действительно не понимаю на данном этапе, так это почему все методы, которые теперь используют бомбу FindBy, выходят с NoSuchElementExceptions. Когда я отлаживаю с помощью точек останова, тест проходит нормально. Итак, есть проблема с синхронизацией с FindBy's. Дело в том, что initElements пытается найти локаторы до того, как WebDriver перейдет на соответствующую страницу или область страницы? В соответствии с тестом я ссылаюсь на несколько разных объектов PageObject, поэтому некоторые из FindBy могут попытаться инициализироваться до загрузки страницы? - person Steerpike; 31.08.2016
comment
Неважно, где вы инициализируете объекты PageObject, потому что PageFactory.initElements предоставляет только прокси для полей WebElement, помеченных аннотацией @FindBy. Но когда вы получаете доступ к этим полям для таких методов, как sendkeys или click, вы должны убедиться, что браузер находится на правильной странице. Вы можете сравнить текущий URL-адрес с тем, что вы хотите для PageObject, или же взглянуть на класс LoadableComponent. Если вы получаете NoSuchElementExceptions, которые исчезают в режиме отладки, вам нужно использовать классы WebDriverWait и ExpectedConditions для правильной синхронизации. - person Grasshopper; 31.08.2016
comment
Спасибо. Это имеет смысл. Я обновил код текущей реализацией и подробностями о том, где генерируется исключение. Не совсем уверен, почему мой вызов «waitForIsDisplayed» не соблюдается — это локатор «searchResults», который невозможно найти, но он пытается найти его до загрузки этой страницы. SearchResultsPage — это отдельный объект PageObject. - person Steerpike; 01.09.2016
comment
Ваш класс PageBase неверен. Вы возвращаете новый экземпляр, а не тот, который вызывается PageFactory.initElements. - person Grasshopper; 01.09.2016
comment
... это просто не нравится: waitForIsDisplayed(searchResults, 120); по какой-то причине - person Steerpike; 01.09.2016
comment
В классе TestBase у вас есть функция щелчка, которая ожидает, прежде чем вы нажмете кнопку. public void click (элемент WebElement) { waitForIsDisplayed (элемент, 120); элемент.щелчок(); } Удалите оттуда waitisDisplayed. - person Grasshopper; 01.09.2016
comment
Не обращайте внимания на предыдущий комментарий. - person Grasshopper; 01.09.2016
comment
Думаю, это объясняет то, что я вижу. Необходимо найти другой метод ожидания: amitstechblog.wordpress.com /24.07.2011/ - person Steerpike; 01.09.2016
comment
Правилен ли локатор для элемента searchResults? Вы проверяли это в браузере вручную? Здесь работает Thread.sleep() вместо ожидания? Попробуйте с этим условием видимостиOfElementLocated(по локатору)? - person Grasshopper; 01.09.2016
comment
Локатор хороший. Сон потока работает. Но когда я меняю метод (и селектор) на использование visibleOfElementLocated(By locator), я получаю такое же нежелательное поведение. Я могу поймать UndeclaredThrowableException, но по какой-то причине ожидание не соблюдается, поэтому утверждение всегда терпит неудачу. - person Steerpike; 01.09.2016
comment
Я обнаружил, что проблема возникла, когда я создавал новый прокси-экземпляр WebDriver. Как только я удалил это и использовал более простой локальный экземпляр = проблема решена - person Steerpike; 01.09.2016

Имя переменной в вашем @FindBydrioDownLocator, а вы передаете — dropDownContainer. Есть ли в вашем классе другая переменная с типом WebElement?

person QA Square    schedule 30.08.2016