WebDriver:如何检查页面对象Web元素是否存在?

时间:2011-06-30 10:48:42

标签: java testing webdriver selenium-webdriver

当使用带有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;
        }
    }
 }

但是我无法相信这种尝试/捕获是人们应该这样做的方式。 那么检查元素是否退出(使用页面对象)的更好方法是什么?

9 个答案:

答案 0 :(得分:5)

问题在于模式本身。它使用@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,则必须使用类似的方法替换ElementLocator中的findElement()方法:

...
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
   }
}

答案 1 :(得分:4)

如果找不到元素,Webdriver被设计为抛出异常,因此没有任何方法可以验证Webdriver中是否存在元素。

检查一下 - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341

答案 2 :(得分:1)

我正在使用这种模式,对我来说很好用:

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;
    }
}

答案 3 :(得分:1)

我最近遇到了这个老帖子,并且相信我找到了一个解决方案。

我正在测试一个有Add User按钮的网页。单击该按钮时,会出现各种可编辑的文本字段(对于名字,姓氏,电子邮件等)和单个下拉列表。

单击Cancel按钮后,字段消失,不再存在。将WebDriverWaitExpectedConditions.visibilityOf()一起使用将无效,因为DOM中不再存在这些元素。

我发现@FindAll对我来说是一个解决方案,但我必须承认我的测试在我的List断言中运行得非常慢。

对于您的代码,如下所示:

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");}

我可以在我自己的测试中使用类似的东西,但它似乎是一种可靠的方式来避免这样的元素&#39;例外。它基本上是一个页面对象改编的断言:driver.findElements(By.locator).size() < 1

答案 4 :(得分:1)

这是访问页面上可选元素的一个很好的模式:

@FindBy(...)
private List<WebElement> element;

public Optional<WebElement> getElement() {
    return element.stream().findFirst();
}

在测试中,您可以使用以下断言:

assertEquals(Optional.empty(), page.getElement()); // element should be absent

assertTrue(page.getElement().isPresent()); // element should be present

var e = page.getElement().orElseThrow(AssertionFailedError::new); // check and use element

答案 5 :(得分:0)

Arquillian已在Graphene扩展程序中实现了该功能。

检查ElementLocatorConditionFactory.isPresent()功能。

他们或多或少做你在问题中所写的内容(来自ExpectedConditions.findElement in selenium-support.jar):

try {
    return driver.findElement(by);
} catch (NoSuchElementException e) {
    throw e;
} catch (WebDriverException e) {
    // [...] some log
    throw e;
}

答案 6 :(得分:0)

@Ralph :我这样做:try / catch。我从未找到另一种方式。 您可以在超类中换出try / catch块并将其设计为 generic 。换句话说:您可以编写一个期望类型为 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

答案 7 :(得分:0)

使用C#绑定:

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(),则在列表上调用IWebElement,评估结果为真。

答案 8 :(得分:-1)

尝试这是在pom中的挑衅

public boolean isPrebuiltTestButtonVisible() {
    try {

        if (preBuiltTestButton.isEnabled()) {

            return true;

        } else {

            return false;
        }

    } catch (Exception e) {

        e.printStackTrace();
        return false;
    }
}

这肯定会在页面对象模型环绕中使用try catch