WebDriver:检查元素是不是存在? [复制]

Posted

技术标签:

【中文标题】WebDriver:检查元素是不是存在? [复制]【英文标题】: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;

【问题讨论】:

@Michael Freidgeim:在你指责某人写了一个重复的问题之前,请检查问题的创建日期以确定哪个是重复的。 我不怪你。这只是一种整理方式——将相似的问题联系在一起。参见Should I vote to close a duplicate question, even though it's much newer, and has more up to date answers?“如果新问题是更好的问题或有更好的答案,那么投票关闭旧问题作为新问题的副本。” 【参考方案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 或其他任何内容的重载选项。这就是为什么我更喜欢这个解决方案而不是其他解决方案。

    返回元素列表然后检查列表大小是否为 0 有效,但这样会失去功能。即使集合大小为 1,您也不能对链接集合执行 .click()。 您可以断言该元素存在,但通常会停止您的测试。在某些情况下,我有一个额外的链接可供点击,具体取决于我进入该页面的方式,如果它存在,我想点击它,否则继续前进。 只有不设置超时才会慢driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));

    它实际上是一个非常简单和优雅的方法一旦创建。通过使用 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)

像这样:

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

这是我的代码:

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】:

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

【讨论】:

以上是关于WebDriver:检查元素是不是存在? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Selenium Webdriver:如何检查特定屏幕上是不是存在 ui 元素,无论它当前是不是可见/可点击

如何检查附加元素是不是已存在? [复制]

如何使用 WebDriver 检查是不是存在警报?

如何使用 WebDriver 检查元素是不是可见

Webdriver - 如何检查浏览器是不是仍然存在或仍然打开?

如何使用 Selenium WebDriver 检查元素是不是可点击