Пытаюсь автоматизировать тестирование одной страницы, но из-за динамического содержимого совсем запутался. Использую Selenium WebDriver +IE+ Java + Page Object
Есть базовая страница, на ней помимо текстовых полей присутствуют кнопки которые вызывают окно со списком значений, где можно осуществить поиск и выбрать значение которое потом будет записано в текстовое поле страницы.
Описываю метод установки значения через это окно, методу передаю текстовое значение, он нажимает нужную кнопку, выводит окно, вводит значение в поле поиска, ищет его и выбирает первую запись. Но из-за того что результат поиска отображается с задержкой, получается что элемент иногда выбирается старый элемент.
Как подружить проверку типа ExpectedConditions.textToBePresentInElement и объявленный в Page Object WebElement?
public void setCustomer(String s) {
CustButton.click();
CustSearchField.sendKeys(s);
CustSearchButton.click();
// Тут должно быть ожидание загрузки найденной строки
CustListElement.click();
CustSelectButton.click();
}
Допустим я не буду использовать проверку внутри метода и разделю его на простые операции которые буду вызывать последовательно в самом тесте. Но как тогда в самом тесте реализовать ожидание\проверку что нужная строка отобразилась? wait.until(ExpectedConditions.textToBePresentInElement требует чтобы я передавал локатор, но мне нужно передать WebElement или уже сохраненный локатор в переменной.
Буду признателен за помощь, т.к. с java пока не очень разобрался.
И такие js скрипты всегда на грани фола - есть вероятность что AJAX запрос просто не успеет создаться после какого-нибудь экшена и вызовом этого скрипта.
Читал про FluentWait, но не пробовал использовать. Подскажите как его теперь добавить в текущий код. На текущем этапе у меня ошибка java.lang.NullPointerException. Наверное из-за того что поместил его не в тот класс. Я так же использую AjaxElementLocatorFactory. Структура у меня такая. Основной класс с тестами testex.java, класс с элементами страницы и методами newReq.java и класс AbstractParentPage.java.
Класс AbstractParentPage.java:
public abstract class AbstractParentPage
{
public int DRIVER_WAIT = 30; // 30 seconds
private WebDriver driver;
/*
* Constructor
* @param driver an instance of WebDriver
*/
public AbstractParentPage(WebDriver driver)
{
ElementLocatorFactory finder = new AjaxElementLocatorFactory(driver,DRIVER_WAIT);
PageFactory.initElements(finder, this);
this.driver = driver;
}
// ------ Add services accessible to all pages here ----
public WebElement fluentWait(final By locator) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
});
return element;
}
}
- Если объявляю fluentWait как часть WebElement, то тест не идёт и возникает ошибка, что нельзя найти элемент, хотя на начальном этапе он его и не должен искать, а только при обращении.
Если же использую просто private By xxx = By.cssSelector(""); не указывая потом, что private WebElement Z = fluentWait(xxx); то все работает нормально. Почему так?
- Столкнулся с запросами, когда старый элемент не пропадает, просто через некоторое время они заменяются новой выдачей. Допустим тоже поисковое окно, по умолчанию грузятся какие то записи, при нажатии "поиск", старые записи отображаются пока не будут показаны новые. При использовании fluentWait он сразу жмет на старый элемент. Как правильнее дождаться момента обновления? Можно как-то различить старую выдачу и новую?
А теперь на код с использованием FluetWait, приведённый несколькими постами выше. Правда очень похоже? Так почему не использовать официально рекомендованный WebDriverWait, а строить свой точно такой же?
Спасибо. Подскажите пожалуйста как подружить WebDriverWait, WebElement и Page Object.
В главном классе я написал метод:
public WebElement waitF (By locator){
Wait<WebDriver> wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
return element;
}
Теперь в классе-потомке в котором у меня описана страница я могу объявить элемент через By xxx = By.cssSelector("…");
А потом в методе использовать waitF(xxx).click(); и всё вроде работает.
Но если я захочу объявить WebElement Z = waitF(xxx); тогда тест не работает, т.к. обращение идёт на этапе объявления элемента, но элемента к тому моменту еще нет на странице. Как быть?
Я так же использую AjaxElementLocatorFactory, может быть из-за этого конфликт возникает?
Еще вопрос по поводу использования WebDriverWait. чтобы его использовать его придётся объявлять в каждом методе каждый раз или написать один метод в главном классе? Получается что если я захочу использовать другое условие, допустим ExpectedConditions.textToBePresentInElement, то придётся написать отдельный метод?
Привет!
Я советую вам попробовать библиотеку Selenide. Она основана на Selenium WebDriver и идеально решает как раз такие проблемы, которые вы описываете. С ней ваш код будет выглядеть примерно так:
public void setCustomer(String s) {
CustButton.click();
CustSearchField.sendKeys(s);
CustSearchButton.click();
CustListElement.shouldBe(visible); // ожидает, пока появится элемент
// или CustListElement.shouldHave(text("Результаты")); // ожидает, пока у элемента появится нужный текст
CustListElement.click();
CustSelectButton.click();
}
Как видите, код заметно проще, и не нужно заморачиваться со всякими там ожиданиями, FluentWait’ами и подобной хренью. Можно сконцентрироваться на бизнес-логике.