【问题标题】:WebDriver: check if an element exists? [duplicate]WebDriver:检查元素是否存在? [复制]
【发布时间】:2011-09-25 03:54:45
【问题描述】:

如何通过 web 驱动检查元素是否存在?

使用 try catch 真的是唯一可行的方法吗?

boolean present;
try {
   driver.findElement(By.id("logoutLink"));
   present = true;
} catch (NoSuchElementException e) {
   present = false;
}

【问题讨论】:

标签: java testing webdriver selenium-webdriver


【解决方案1】:

你也可以这样做:

driver.findElements( By.id("...") ).size() != 0

这节省了讨厌的 try/catch

附言

或者更准确地说是@JanHrcek here

!driver.findElements(By.id("...")).isEmpty()

【讨论】:

  • 或者更简洁:!driver.findElements(By.id("...")).isEmpty();
  • 如果元素存在,这些都可以正常工作,否则会花费太多时间
  • 而且大小不是方法——driver.findElements( By.id("...") ).size != 0
  • 这是在 selenium javadoc 中查找不存在元素的推荐方法,以防万一有人需要指向它的指针:selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/…
  • 如果你碰巧像我一样,看着这个并说“什么......?那是调用相同的方法,因此也会抛出异常!?!”......看再次,它的复数形式 - 'findElements'。 ;)
【解决方案2】:

我同意 Mike 的回答,但如果没有找到可以打开/关闭的元素,则需要等待 3 秒,这在您经常执行此操作时很有用:

driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS);
boolean exists = driver.findElements( By.id("...") ).size() != 0
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

如果您正在运行大量测试,将其放入实用程序方法中应该会提高性能

【讨论】:

  • 因为隐式超时可以是3秒,也可以是其他值,所以应该先存储旧值,然后再重新设置。但不幸的是你可以设置值,但不能读取它——cool api
  • 默认的隐式等待时间似乎是 0,(seleniumhq.org/docs/04_webdriver_advanced.html) 所以除非你把它配置得更长,否则这应该是没有必要的。
  • @Ralph 有没有办法获取当前值?
  • 一开始你把它设置在某个地方,你应该自己存储它。也给出了默认值。
【解决方案3】:

正如评论所述,这是用 C# 而不是 Java,但想法是一样的。我已经广泛研究了这个问题,最终问题是,当元素不存在时,FindElement 总是返回异常。没有允许您获取 null 或其他任何内容的重载选项。这就是为什么我更喜欢这个解决方案而不是其他解决方案。

  1. 返回元素列表然后检查列表大小是否为 0 有效,但这样会失去功能。即使集合大小为 1,您也不能对链接集合执行 .click()。
  2. 您可以断言该元素存在,但通常会停止您的测试。在某些情况下,我有一个额外的链接可供点击,具体取决于我进入该页面的方式,如果它存在,我想点击它,否则继续前进。
  3. 只有不设置超时才会慢driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));
  4. 它实际上是一个非常简单和优雅的方法一旦创建。通过使用 FindElementSafe 而不是 FindElement,我不会“看到”丑陋的 try/catch 块,并且可以使用简单的 Exists 方法。看起来像这样:

    IWebElement myLink = driver.FindElementSafe(By.Id("myId"));
    if (myLink.Exists)
    {
       myLink.Click();
    }
    

这是扩展 IWebElement 和 IWebDriver 的方法

IWebDriver.FindElementSafe

    /// <summary>
    /// Same as FindElement only returns null when not found instead of an exception.
    /// </summary>
    /// <param name="driver">current browser instance</param>
    /// <param name="by">The search string for finding element</param>
    /// <returns>Returns element or null if not found</returns>
    public static IWebElement FindElementSafe(this IWebDriver driver, By by)
    {
        try
        {
            return driver.FindElement(by);
        }
        catch (NoSuchElementException)
        {
            return null;
        }
    }

IWebElement.Exists

    /// <summary>
    /// Requires finding element by FindElementSafe(By).
    /// Returns T/F depending on if element is defined or null.
    /// </summary>
    /// <param name="element">Current element</param>
    /// <returns>Returns T/F depending on if element is defined or null.</returns>
    public static bool Exists(this IWebElement element)
    {
        if (element == null)
        { return false; }
        return true;
    }

您可以使用多态性来修改 FindElement 的 IWebDriver 类实例,但从维护的角度来看这是一个坏主意。

【讨论】:

  • 有两个问题:1) 错误的语言:Java 而不是 C#,2) 你使用了丑陋的 try/catch 解决方法(这就是问题所在,如果有比这种丑陋和缓慢的其他方法尝试/捕捉)
  • 是的,那是 C#,但概念是一样的。 Try/Catch 只有在你必须经常这样做时才会变得丑陋。这就是为什么我将它封装在一个单独的方法中。最终的解决方案实际上非常漂亮。 bool 存在 = driver.FindElementSafe(by).Exists();
  • Try/Catch 不仅代码难看,运行时也很慢。用不同的方法封装它可以解决第一个问题,而不是第二个问题。
  • 大声笑,UI 测试并不以速度着称,因此它是“敏捷测试金字塔”的顶端。与在 Chrome 或您正在使用的任何浏览器中获取和呈现页面所需的时间相比,在 try/catch id 中损失的一秒钟的时间相形见绌。如果你担心几分之一秒,那么你做错了测试类型。我建议在这种情况下考虑做更多的单元测试。
【解决方案4】:

这对我每次都有效:

    if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
        //THEN CLICK ON THE SUBMIT BUTTON
    }else{
        //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
    }

【讨论】:

    【解决方案5】:

    我扩展了 Selenium WebDriver 的实现,在我的例子中是 HtmlUnitDriver 来公开一个方法

    public boolean isElementPresent(By by){}
    

    像这样:

    1. 检查页面是否在超时时间内加载。
    2. 加载页面后,我将 WebDriver 的隐式等待时间降低到几毫秒,在我的情况下为 100 毫秒,可能也应该与 0 毫秒一起使用。
    3. 调用 findElements(By),WebDriver 即使找不到元素也只会等待上面的时间量。
    4. 将隐式等待时间缩短以等待未来的页面加载

    这是我的代码:

    import java.util.concurrent.TimeUnit;
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.htmlunit.HtmlUnitDriver;
    import org.openqa.selenium.support.ui.ExpectedCondition;
    import org.openqa.selenium.support.ui.WebDriverWait;
    
    public class CustomHtmlUnitDriver extends HtmlUnitDriver {
    
        public static final long DEFAULT_TIMEOUT_SECONDS = 30;
        private long timeout = DEFAULT_TIMEOUT_SECONDS;
    
        public long getTimeout() {
            return timeout;
        }
        public void setTimeout(long timeout) {
            this.timeout = timeout;
        }
    
        public boolean isElementPresent(By by) {
            boolean isPresent = true;
            waitForLoad();
            //search for elements and check if list is empty
            if (this.findElements(by).isEmpty()) {
                isPresent = false;
            }
            //rise back implicitly wait time
            this.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
            return isPresent;
        }
    
        public void waitForLoad() {
            ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver wd) {
                    //this will tel if page is loaded
                    return "complete".equals(((JavascriptExecutor) wd).executeScript("return document.readyState"));
                }
            };
            WebDriverWait wait = new WebDriverWait(this, timeout);
            //wait for page complete
            wait.until(pageLoadCondition);
            //lower implicitly wait time
            this.manage().timeouts().implicitlyWait(100, TimeUnit.MILLISECONDS);
        }   
    }
    

    用法:

    CustomHtmlUnitDriver wd = new CustomHtmlUnitDriver();
    wd.get("http://example.org");
    if (wd.isElementPresent(By.id("Accept"))) {
        wd.findElement(By.id("Accept")).click();
    }
    else {
        System.out.println("Accept button not found on page");
    }
    

    【讨论】:

      【解决方案6】:

      使用 Java 编写以下方法:

      protected boolean isElementPresent(By by){
              try{
                  driver.findElement(by);
                  return true;
              }
              catch(NoSuchElementException e){
                  return false;
              }
          }
      

      在断言期间调用上述方法。

      【讨论】:

      • 我看不出这是如何回答这个问题的:“使用 try catch 真的是唯一可能的方法吗?”?
      【解决方案7】:

      你可以做一个断言。

      看例子

      driver.asserts().assertElementFound("Page was not loaded",
      By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);
      

      你可以使用这是原生的:

      public static void waitForElementToAppear(Driver driver, By selector, long timeOutInSeconds, String timeOutMessage) {
          try {
            WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
            wait.until(ExpectedConditions.visibilityOfElementLocated(selector));
          } catch (TimeoutException e) {
            throw new IllegalStateException(timeOutMessage);
          }
        }
      

      【讨论】:

      • 这看起来很有趣,但你能澄清一下那是什么驱动程序吗? WebDriver javadocs 不显示 asserts() 方法。
      【解决方案8】:
      String link = driver.findElement(By.linkText(linkText)).getAttribute("href")
      

      这将为您提供元素指向的链接。

      【讨论】:

      • 但是,如果带有文本“linkText”的元素不存在,这将导致 Nullpointer 异常——它最终与 nu1silva 发布的相同的无效想法
      【解决方案9】:

      使用 selenium-java.jar 的 2.21.0 版本,您可以做到这一点;

      driver.findElement(By.id("...")).isDisplayed()
      

      【讨论】:

      • 你确定:我希望driver.findElement(By.id("...")) 抛出异常。
      • 它确实仍然抛出异常 nin 2.21.0 OpenQA.Selenium.NoSuchElementException : Unable to locate element: {"method":"id","selector":"FormButtonPanel_ButtonCancel"} 命令持续时间或超时: 4 毫秒有关此错误的文档,请访问:seleniumhq.org/exceptions/no_such_element.html 构建信息:版本:'2.21.0',修订:'16552',时间:'2012-04-11 19:08:38' 系统信息:os .name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_22' 驱动信息: driver.version: EventFiringWebDriver
      • -1 这是错误的。 isDisplayed 可用于测试元素是否现在可见,而不是它是否存在于 dom 中。
      • -1 这与页面上是否存在元素是一回事。
      【解决方案10】:

      据我了解,这是使用网络驱动程序的默认方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-19
        • 2013-10-30
        • 2011-06-15
        • 2015-09-09
        • 2014-02-17
        • 2012-11-20
        相关资源
        最近更新 更多