WebDriver:检查元素是否存在?

Ral*_*lph 121 java testing webdriver selenium-webdriver

如何检查Web驱动程序是否存在元素?

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

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

Mik*_*wan 229

你也可以这样做:

driver.findElements( By.id("...") ).size() != 0
Run Code Online (Sandbox Code Playgroud)

这节省了令人讨厌的尝试/捕获

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

Edd*_*Edd 50

我同意迈克的回答,但是如果没有找到可以打开/关闭的元素,则会有一个隐含的3秒等待,如果您执行此操作很多很有用:

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

如果您正在运行大量测试,那么将它放入实用程序方法应该可以提高性能

  • 因为implicite超时可以是3秒,但也是另一个值,一个可以先存储旧值,然后重新设置它.但不幸的是你可以设置值,但不能读它 - 很酷的api (6认同)
  • 似乎默认的隐式等待时间为0,(http://seleniumhq.org/docs/04_webdriver_advanced.html)因此,除非您将其配置为更长,否则这不是必需的. (4认同)

Bra*_*ard 8

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

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

    IWebElement myLink = driver.FindElementSafe(By.Id("myId"));
    if (myLink.Exists)
    {
       myLink.Click();
    }
    
    Run Code Online (Sandbox Code Playgroud)

以下是扩展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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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;
    }
Run Code Online (Sandbox Code Playgroud)

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

  • 大声笑,UI测试不知道速度,因此它是"敏捷测试金字塔"的顶部.在try/catch id中丢失的一小部分与在Chrome或您正在使用的任何浏览器中获取和呈现页面所花费的时间相比相形见绌.如果你担心几分之一秒,你就会做错误的测试.在这种情况下,我建议考虑进行更多的单元测试. (8认同)
  • 是的,这是C#,但概念是一样的.如果你经常这样做,尝试/捕获只是丑陋.这就是我将其封装在一个单独的方法中的原因.最终的解决方案实际上非常漂亮.bool exists = driver.FindElementSafe(by).Exists(); (5认同)
  • 有两个问题:1)语言错误:Java不是C#,2)你使用了丑陋的try/catch解决方法(这就是问题,如果还有另一种方法,那就是这个丑陋而缓慢的try/catch) (3认同)

Lot*_*tzy 5

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

public boolean isElementPresent(By by){}
Run Code Online (Sandbox Code Playgroud)

像这样:

  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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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");
}
Run Code Online (Sandbox Code Playgroud)


小智 5

每次都对我有用:

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