Java WebDriver:检查元素是否存在?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6521270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:36:33  来源:igfitidea点击:

WebDriver: check if an element exists?

javatestingwebdriverselenium-webdriver

提问by Ralph

How to check if an element exist with web driver?

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

Is using a try catch really the only possible way?

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

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

采纳答案by Mike Kwan

You could alternatively do:

你也可以这样做:

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

Which saves the nasty try/catch

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

回答by P?l Brattberg

As I understand it, this is the default way of using the web driver.

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

回答by Edd

I agree with Mike's answer but there's an implicit 3 second wait if no elements are found which can be switched on/off which is useful if you're performing this action a lot:

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

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

Putting that into a utility method should improve performance if you're running a lot of tests

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

回答by nu1silva

With version 2.21.0 of selenium-java.jar you can do this;

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

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

回答by user1549161

String link = driver.findElement(By.linkText(linkText)).getAttribute("href")

This will give you the link the element is pointing to.

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

回答by Ran Adler

you can do an assertion.

你可以做一个断言。

see the example

看例子

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

you can use this this is native :

你可以使用这是原生的:

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

回答by Brantley Blanchard

As the comment stated, this is in C# not Java but the idea is the same. I've researched this issue extensively and ultimately the issue is, FindElement always returns an exception when the element doesn't exist. There isn't an overloaded option that allows you to get null or anything else. Here is why I prefer this solution over others.

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

  1. Returning a list of elements then checking if the list size is 0 works but you lose functionality that way. You can't do a .click() on a collection of links even if the collection size is 1.
  2. You could assert that the element exists but often that stops your testing. In some cases, I have an extra link to click depending on how I got to that page and I want to click it if it exists or move on otherwise.
  3. It's only slow if you don't set the timeout driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));
  4. It's actually a very simple and elegant once the method is created. By using FindElementSafeinstead of FindElement, I don't "see" the ugly try/catch block and I can use a simple Existsmethod. That would look something like this:

    IWebElement myLink = driver.FindElementSafe(By.Id("myId"));
    if (myLink.Exists)
    {
       myLink.Click();
    }
    
  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();
    }
    

Here is how you extend IWebElement & IWebDriver

这是扩展 IWebElement 和 IWebDriver 的方法

IWebDriver.FindElementSafe

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

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

You could use polymorphism to modify the IWebDriver class instance of FindElement but that's a bad idea from a maintenance standpoint.

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

回答by Lotzy

I extended Selenium WebDriver implementation, in my case HtmlUnitDriver to expose a method

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

public boolean isElementPresent(By by){}

like this:

像这样:

  1. check if page is loaded within a timeout period.
  2. Once page is loaded, I lower the implicitly wait time of the WebDriver to some milliseconds, in my case 100 mills, probably should work with 0 mills too.
  3. call findElements(By), the WebDriver even if will not find the element will wait only the amount of time from above.
  4. rise back the implicitly wait time for future page loading
  1. 检查页面是否在超时时间内加载。
  2. 加载页面后,我将 WebDriver 的隐式等待时间降低到几毫秒,在我的情况下为 100 mills,可能也应该使用 0 mills。
  3. 调用 findElements(By),WebDriver 即使不会找到元素也只会从上面等待一段时间。
  4. 提高未来页面加载的隐式等待时间

Here is my code:

这是我的代码:

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

Usage:

用法:

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

回答by Amstel Bytes

This works for me every time:

这每次都对我有用:

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

回答by Ripon Al Wasim

Write the following method using Java:

使用 Java 编写以下方法:

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

Call the above method during assertion.

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