使用Selenium WebDriver测试元素是否存在?


163

有没有一种方法可以测试元素是否存在?任何findElement方法都将以异常结尾,但这不是我想要的,因为它可能是一个元素不存在并且没关系,这不是测试失败,所以异常不能成为解决方案。

我发现了这篇文章:Selenium c#Webdriver:等待元素出现, 但这是针对C#的,我不是很擅长。谁能将代码翻译成Java?抱歉,我在Eclipse中进行了尝试,但我没有将其正确地插入Java代码中。

这是代码:

public static class WebDriverExtensions{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds){

        if (timeoutInSeconds > 0){
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }

        return driver.FindElement(by);
    }
}

我有几种方法可以非常有效地检查对象,但这取决于您要使用的对象。例如,您要在元素存在之前寻找它,还是要在元素不再存在之前寻找它,还是想尝试找到它?
CBRRacer 2011年

1
Java与C#非常相似,我认为您在这里遇到的主要问题之一是在Java中,它是WebElement而不是IWebElement
CBRRacer 2011年

您知道隐式等待方法吗?通过在测试开始时进行设置,您无需检查元素是否存在,因为它使用隐式等待值进行轮询,但是,如果该值超过该值,则将引发异常
Bob Evans

这是我有关Java中WebDriverWait的

如果任何一种情况都可以,那么这可能会给测试性能带来问题,因为等待您不希望存在的元素的等待时间确实增加了。我使用了一些技巧来解决等待时间,但是还没有找到一个真正干净的解决方案。
mrfreester 2014年

Answers:


277

使用findElements代替findElement

findElements 如果没有找到匹配的元素,则返回一个空列表,而不是一个异常。

要检查是否存在某个元素,可以尝试执行此操作

Boolean isPresent = driver.findElements(By.yourLocator).size() > 0

如果找到至少一个元素,则返回true;否则,返回false。

官方文档推荐此方法:

findElement不应用于查找不存在的元素,而应使用findElements(By)并声明零长度响应。


32
这将增加运行测试所需的时间。您不能在所有地方都使用此技术。
Droogans 2012年

8
@Droogans-我不会为您的测试增加时间。之所以不会,是因为默认的隐式等待仍为0。如果您增加了默认的隐式等待,那么我同意这样做,但是在这里似乎并非如此。
djangofan,2015年

1
好的djangofan!通过将驱动程序超时的隐式等待时间更改为零,然后将其更改回其先前的值,我成功地使用了此策略。
2015年

3
这给了NoSuchElementFound异常,这很可惜,因为我希望使用它来避免在给定实例中捕获该异常。

1
更简单的方法是使用:if(driver.getPageSource()。contains(“页面中的文本”)){}如果页面包含此文本,则条件为true,否则为false,您可以编写代码相应地。
pradyot '18

56

那么只需要查找元素并确定其是否存在的私有方法呢?

private boolean existsElement(String id) {
    try {
        driver.findElement(By.id(id));
    } catch (NoSuchElementException e) {
        return false;
    }
    return true;
}

这将非常容易并且可以完成工作。

编辑:您甚至可以更进一步,并采用By elementLocatoras作为参数,如果要通过id以外的其他元素查找元素,则可以消除问题。


3
是的,这是要走的路。不明白为什么人们都忽略了这种方式,和计数匹配的元素,看是否结果为0
拉尔夫·拉维尔

45
好吧,我必须说,使用异常来规范程序流并不是最好的方法。
丹尼斯2014年

2
??这是你的建议!如果您的测试希望找不到元素,那么这是一个很好的方法。如您所示,仅返回null和assert.isnull或isnotnull,这是测试事物是否存在的一种有意义的方法。
拉尔夫·拉维尔

2
万一我误解了问题“有没有一种方法可以测试元素是否存在?” 是的,我很高兴得知您对这是否是合法答案的意见为何不同。
丹尼斯

可能希望减少等待时间。现在,如果该元素不存在,则必须等待“ 30秒”,然后该函数返回false
Jason Smiley 2015年

14

我发现这适用于Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);

18
presenceOfElementLocated如果在任何特定尝试中都找不到该元素,则将抛出Exception。为避免这种情况,请wait.ignoring(NoSuchElementException.class);在第一行和第二行之间添加一条语句。
史蒂夫·钱伯斯

8
public static WebElement FindElement(WebDriver driver, By by, int timeoutInSeconds)
{
    WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
    wait.until( ExpectedConditions.presenceOfElementLocated(by) ); //throws a timeout exception if element not present after waiting <timeoutInSeconds> seconds
    return driver.findElement(by);
}

5

我遇到过同样的问题。对我来说,根据用户的权限级别,某些链接,按钮和其他元素将不会显示在页面上。我的套件的一部分正在测试应丢失的元素是否丢失。我花了几个小时试图解决这个问题。我终于找到了完美的解决方案。

这样做是告诉浏览器查找指定的所有元素。如果结果为0,则表示未找到基于规范的元素。然后,我让代码执行一条if语句,让我知道未找到它。

这是已经存在的C#,因此需要对进行翻译Java。但不应该太辛苦。

public void verifyPermission(string link)
{
    IList<IWebElement> adminPermissions = driver.FindElements(By.CssSelector(link));
    if (adminPermissions.Count == 0)
    {
        Console.WriteLine("User's permission properly hidden");
    }
}

您还可以根据您的测试需求采取另一种方法。

以下代码段正在检查页面上是否存在非常特定的元素。根据元素的存在,我让测试执行if。

如果该元素存在并显示在页面上,请console.write让我知道并继续。如果存在相关元素,那么我将无法执行所需的测试,这是需要进行此设置的主要原因。

如果元素不存在,并且不显示在页面上。我在其他情况下执行其他测试。

IList<IWebElement> deviceNotFound = driver.FindElements(By.CssSelector("CSS LINK GOES HERE"));
//if the element specified above results in more than 0 elements and is displayed on page execute the following, otherwise execute whats in the else statement
if (deviceNotFound.Count > 0 && deviceNotFound[0].Displayed){
    //script to execute if element is found
} else {
    //Test script goes here.
}

我知道我对OP的回应有点晚了。希望这可以帮助某人!


5

尝试以下操作:调用此方法并传递3个参数:

  1. WebDriver变量。//假设driver_variable为驱动程序。
  2. 您要检查的元素。应提供By方法。//例如:By.id(“ id”)
  3. 时间限制(以秒为单位)。

示例:waitForElementPresent(driver,By.id(“ id”),10);

public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {

        WebElement element; 

        try{
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait() 

            WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds); 
            element = wait.until(ExpectedConditions.presenceOfElementLocated(by));

            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //reset implicitlyWait
            return element; //return the element
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null; 
    }

3

通过在try catch语句之前缩短硒超时,可以使代码运行更快。

我使用以下代码检查是否存在元素。

protected boolean isElementPresent(By selector) {
    selenium.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    logger.debug("Is element present"+selector);
    boolean returnVal = true;
    try{
        selenium.findElement(selector);
    } catch (NoSuchElementException e){
        returnVal = false;
    } finally {
        selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
    }
    return returnVal;
}

这就是我在代码中使用的。我将Selenium超时保留为默认值,然后使用它。
Nicholas DiPiazza 2015年

2
自编写此答案以来,我了解到使用ExpectedConditions被认为是更好的形式,但是在尝试确定是否不存在元素时,使用try catch语句仍然有用。
EsotericNonsense 2015年

我被困在旧版本的硒中,因为我必须测试IE8。但我会尝试在可以升级时进行
Nicholas DiPiazza

每次您的方法将设置隐式等待超时,但是从逻辑上讲,我们应该在初始化驱动程序对象并将超时设置为驱动程序会话后仅设置一次隐式等待。
Shekhar Swami,2016年

3

使用Java编写以下函数/方法:

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

在断言期间使用适当的参数调用该方法。


2

如果您在ruby中使用rspec-Webdriver,则可以使用此脚本,假定确实不应该存在某个元素,并且它是通过测试。

首先,首先从您的类RB文件中编写此方法

class Test
 def element_present?
    begin
        browser.find_element(:name, "this_element_id".displayed?
        rescue Selenium::WebDriver::Error::NoSuchElementError
            puts "this element should not be present"
        end
 end

然后,在您的规范文件上,调用该方法。

  before(:all) do    
    @Test= Test.new(@browser)
  end

 @Test.element_present?.should == nil

如果您的元素不存在,那么您的规格将通过,但是如果该元素存在,它将引发错误,测试失败。


2

这对我有用:

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

这里存在相同的问题:如果元素“ // * [@ id ='submit']”不存在怎么办?则将引发异常,因此如果条件从不评估
MrBCut


1

就个人而言,我总是将以上答案混合在一起,并创建一个使用size() > 0建议的可重用静态实用程序方法:

public Class Utility {
   ...
   public static boolean isElementExist(WebDriver driver, By by) {
      return driver.findElements(by).size() > 0;
   ...
}

这是整洁,可重用,可维护的……所有这些好东西;-)


0

若要查找是否存在特定的元素,我们必须使用findElements()方法而不是findElement()。

int i=driver.findElements(By.xpath(".......")).size();
if(i=0)
System.out.println("Element is not present");
else
System.out.println("Element is present");

这对我有用..如果我错了建议我..


0

应该这样做:

try {
    driver.findElement(By.id(id));
} catch (NoSuchElementException e) {
    //do what you need here if you were expecting
    //the element wouldn't exist
}

0

提供我的代码段。因此,以下方法检查页面上是否存在随机Web元素“ 创建新应用程序 ”按钮。请注意,我将等待时间设为0秒。

public boolean isCreateNewApplicationButtonVisible(){
    WebDriverWait zeroWait = new WebDriverWait(driver, 0);
    ExpectedCondition<WebElement> c = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@value='Create New Application']"));
    try {
        zeroWait.until(c);
        logger.debug("Create New Application button is visible");
        return true;
    } catch (TimeoutException e) {
        logger.debug("Create New Application button is not visible");
        return false;
    }
}

0

我会使用类似的东西(使用Scala [旧的“好” Java 8中的代码可能与此类似]):

object SeleniumFacade {

  def getElement(bySelector: By, maybeParent: Option[WebElement] = None, withIndex: Int = 0)(implicit driver: RemoteWebDriver): Option[WebElement] = {
    val elements = maybeParent match {
      case Some(parent) => parent.findElements(bySelector).asScala
      case None => driver.findElements(bySelector).asScala
    }
    if (elements.nonEmpty) {
      Try { Some(elements(withIndex)) } getOrElse None
    } else None
  }
  ...
}

所以呢

val maybeHeaderLink = SeleniumFacade getElement(By.xpath(".//a"), Some(someParentElement))

0

我在Java中找到的最简单方法是:

List<WebElement> linkSearch=  driver.findElements(By.id("linkTag"));
int checkLink=linkSearch.size();
if(checkLink!=0){  //do something you want}

0

您可以尝试隐式等待:

WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

或者您可以尝试显式等待一个:

IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
    {
        return d.FindElement(By.Id("someDynamicElement"));
    });

显式将在执行某些操作之前检查是否存在element。隐式等待可以在代码中的每个位置调用。例如,在执行一些AJAX操作之后。

您可以在SeleniumHQ页面上找到更多信息

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.