Ответ 1
Webdriver предназначен для генерирования исключения, если элемент не найден, поэтому нет никаких методов проверки наличия элемента в Webdriver.
Проверьте это - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341
Как проверить, существует ли Элемент, при использовании Объектов страницы с webdriver.
Пока я делаю это так.
DefaultPage defaultPage = PageFactory.initElements(this.driver,
DefaultPage.class);
assertTrue(defaultPage.isUserCreateMenuLinkPresent());
Объект страницы:
public class DefaultPage {
@FindBy(id = "link_i_user_create")
private WebElement userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
try {
this.userCreateMenuLink.getTagName();
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
Но я не могу поверить, что эта попытка/улов - это то, как это нужно делать. Итак, что было бы лучшим способом проверить, не выходят ли элементы (с использованием объектов страницы)?
Webdriver предназначен для генерирования исключения, если элемент не найден, поэтому нет никаких методов проверки наличия элемента в Webdriver.
Проверьте это - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341
Проблема заключается в самом шаблоне. Он использует аннотацию @FindBy (используется PageFactory для инициализации полей, которые должны быть обернуты Proxy), которая заменяет стандартные элементы их экземплярами прокси, которые содержат InvocationHandler.
Каждый раз, когда вы пытаетесь получить доступ к полю, аннотируемому с помощью @FindBy, обработчик вызова пытается найти элемент, используя ElementLocator по умолчанию. Проблема заключается в том, что метод ElementLocator.findElement() генерирует исключение TimeoutException/NoSuchElementException, если нет элементы, представленные в DOM.
public WebElement findElement(SearchContext context) {
List<WebElement> allElements = findElements(context);
if (allElements == null || allElements.isEmpty())
throw new NoSuchElementException("Cannot locate an element using "
+ toString());
return allElements.get(0);
}
Поэтому каждый раз, когда вам нужно проверить, отображается ли элемент или нет, вам нужно найти список элементов и проверить его размер.
@FindBy(css = "div.custom")
private List<WebElement> elements
...
public isElementPresented(){
return elements != null && elements.size > 0
}
Еще один способ решить эту проблему - создать собственную реализацию LocatingElementHandler и ElementLocator
Итак, если вам нужен собственный метод isDisplayed() для возврата false вместо Exception, вам необходимо заменить метод findElement() в ElementLocator примерно таким:
...
List<WebElement> elements = searchContext.findElements(by)
if(elements != null && elements.size() > 0){
List<WebElement> visibleElements = []
elements.each {
if(it.displayed){
visibleElements.add(it)
}
}
if(visibleElements.size() > 0){
return visibleElements.get(0)
}
}
return null
...
И добавьте новые условия в LocatingElementHandler.invoke()
Что-то вроде:
element = locator.findElement()
if(element == null){
if(method.name == "isDisplayed"){
return false
}
}
Я использую этот шаблон, отлично работает для меня:
public void login()
{
if (!loginButton.isDisplayed())
{
throw new IllegalStateException("Login button is not displayed!");
} else
{
loginButton.click();
}
}
или
public boolean loginButtinIsDisplayed() {
try {
this.loginButton.getTagName();
return true;
} catch (NoSuchElementException e) {
e.printStackTrace();
return false;
}
}
@Ralph: Я делаю это точно так же: try/catch. Я никогда не находил другого пути. Вы можете поменять блок try/catch в суперкласс и создать его общий. Другими словами: вы можете написать метод, который ожидает объект типа WebElement. Этот метод содержит блок try/catch и возвращает true/false...
Итак, я написал следующий открытый метод в тестовом фреймворке суперкласс, и теперь я могу использовать его в каждом объекте страницы:
public boolean isElementExisting(WebElement we) {
try {
we.isDisplayed();
return true;
} catch(NoSuchElementException e) {
LOGGER.severe("Element does not exist.");
return false;
}
}
Я не знаю, почему это не реализовано в WebDriver...
В противном случае вы можете использовать WebDriverWait.
Недавно я столкнулся с этим старым сообщением и считаю, что нашел одно решение.
Я тестировал страницу с кнопкой Add User
. Когда кнопка была нажата, появились различные редактируемые текстовые поля (для имени, фамилии, электронной почты и т.д.) И одного раскрывающегося списка.
Когда нажата кнопка Cancel
, поля исчезли и больше не существовали. Использование WebDriverWait
с ExpectedConditions.visibilityOf()
не будет работать, поскольку в DOM
элементы больше не существовали.
Я обнаружил, что @FindAll
был для меня решением, хотя я должен признать, что мой тест заметно замедлился в моем утверждении списка.
Для вашего кода, примерно так:
public class DefaultPage {
@FindAll({@FindBy(id = "link_i_user_create")}) List<WebElement> userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
if (this.userCreateMenuLink.isEmpty()) fail("Link does not exist");}
Я могу использовать что-то подобное в своих собственных тестах, но, похоже, надежный способ сгладить исключение "Нет такого элемента". Это в основном адаптация объекта страницы утверждения: driver.findElements(By.locator).size() < 1
.
Использование привязок С#:
using System.Collections.Generic;
using System.Linq;
public class DefaultPage
{
[FindsBy(How = How.Id, Using = "link_i_user_create")]
private IList<IWebElement> userCreateMenuLink;
public bool isUserCreateMenuLinkPresent()
{
return userCreateMenuLink.Any();
}
}
Вы говорите Selenium, чтобы захватить все элементы, которые соответствуют этому Id, и помещают их в Список IWebElement
. Затем вы вызываете .Any()
в список, который оценивает значение true, если найдено хотя бы один IWebElement
.
Arquillian внедрил эту функцию в Graphene.
Отметьте ElementLocatorConditionFactory.isPresent()
.
Они более или менее делают то, что вы написали в своем вопросе (из ExpectedConditions.findElement
в selenium-support.jar):
try {
return driver.findElement(by);
} catch (NoSuchElementException e) {
throw e;
} catch (WebDriverException e) {
// [...] some log
throw e;
}
попробуйте, чтобы это вызывающе работало в pom
public boolean isPrebuiltTestButtonVisible() {
try {
if (preBuiltTestButton.isEnabled()) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
это, безусловно, будет работать в окружении объектной модели страницы с помощью try catch