【问题标题】:Test if element is present using Selenium WebDriver?使用 Selenium WebDriver 测试元素是否存在?
【发布时间】:2011-12-20 22:46:10
【问题描述】:

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

我发现了这个帖子:Selenium c# Webdriver: Wait Until Element is Present 但这是针对 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);
    }
}

【问题讨论】:

  • 我有几个方法可以非常有效地检查对象,但这取决于你想用它做什么。例如,您要查找元素直到它存在,您要查找它直到它不再存在,还是只想尝试找到它?
  • Java 与 C# 非常相似,我认为您在这里遇到的主要问题之一是在 java 中它是 WebElement 而不是 IWebElement
  • 你知道隐式等待方法吗?通过在测试开始时进行设置,您不必检查元素是否存在,因为它使用隐式等待值进行轮询,但是如果它超过该值,它将引发异常
  • 这是我关于 Java 中的 WebDriverWait 的帖子:WebDriverWait
  • 如果任何一种情况都可以,这可能会给测试性能带来问题,因为与等待您不希望存在的元素相关的等待时间确实会增加。我已经使用了一些技巧来绕过等待时间,但还没有找到真正干净的解决方案。

标签: java selenium selenium-webdriver


【解决方案1】:
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);
}

【讨论】:

    【解决方案2】:

    使用findElements 而不是findElement

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

    要检查一个元素是否存在,你可以试试这个

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

    如果至少找到一个元素,则返回 true,如果不存在,则返回 false。

    The official documentation推荐这种方法:

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

    【讨论】:

    • 这将增加运行测试所需的大量时间。你不能到处使用这种技术。
    • @Droogans - 我不会为你的测试增加时间。之所以不会是因为默认的隐式等待仍然是0。如果你增加了默认的隐式等待,那么我同意它会,但这里似乎不是这样。
    • 好叫 djangofan!通过将驱动程序超时的隐式等待更改为零,然后将其更改回之前的值,我成功地使用了此策略。
    • 这给出了 NoSuchElementFound 异常,这很遗憾,因为我希望使用它来避免在给定实例中捕获该异常。
    • 更简单的方法是使用: if(driver.getPageSource().contains("A text in page")){} 如果页面包含此文本,则条件为真,否则这将是错误的,您可以进行相应的编码。
    【解决方案3】:

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

    它的作用是告诉浏览器查找任何和所有基于指定的元素。如果结果为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");
        }
    }
    

    根据您的测试需要,您还可以选择另一条路径。

    下面的 sn-p 正在检查页面上是否存在非常特定的元素。根据元素的存在,我让测试执行 if else。

    如果元素存在并显示在页面上,我有console.write 让我知道并继续前进。如果存在问题的元素,我无法执行我需要的测试,这是需要设置它的主要原因。

    如果元素不存在,并且不显示在页面上。我在 if else 中有 else 执行测试。

    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 的回复有点晚了。希望这可以帮助某人!

    【讨论】:

      【解决方案4】:

      一个简单地查找元素并确定它是否存在的私有方法是这样的:

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

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

      编辑:您甚至可以更进一步,将By elementLocator 作为参数,如果您想通过 id 以外的其他方式查找元素,则可以消除问题。

      【讨论】:

      • 是的,这就是要走的路。不明白为什么人们都忽略这种方式,并且计数匹配元素,看看结果是否为0。
      • 好吧,我必须说使用异常来规范程序流程并不是最好的方法。
      • 嗯?是你的建议!如果您的测试不希望找到该元素,这是一个很好的方法。如您所见,只需返回 null 和 assert.isnull 或 isnotnull,这是测试事物是否存在的一种有意义的方式。
      • 如果我误解了“有没有办法测试元素是否存在?”这个问题。错了,我很高兴知道为什么你对这是否是一个合法的答案有不同的看法。
      • 可能想要减少等待时间。现在,如果元素不存在,则必须等待“30 秒”,然后函数才会返回 false
      【解决方案5】:

      我发现这适用于 Java:

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

      【讨论】:

      • presenceOfElementLocated 如果在任何特定尝试中都找不到该元素,则会抛出异常。为避免这种情况,请在第一行和第二行之间添加 wait.ignoring(NoSuchElementException.class); 语句。
      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        要查找特定元素是否存在,我们必须使用 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");
        

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

        【讨论】:

          【解决方案8】:

          如果您在 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
          

          如果您的元素不存在,您的规范将通过,但如果元素存在,则会抛出错误,测试失败。

          【讨论】:

            【解决方案9】:

            应该这样做:

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

            【讨论】:

              【解决方案10】:

              你可以试试隐式等待:

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

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

              您可以在SeleniumHQ page找到更多信息

              【讨论】:

                【解决方案11】:

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

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

                这是整洁、可重复使用、可维护的......所有这些好东西;-)

                【讨论】:

                • 很好,但是如何等待结果大小?如何设置 size() > 0 的时间
                【解决方案12】:

                试试这个: 调用此方法并传递 3 个参数:

                1. WebDriver 变量。 // 假设 driver_variable 作为驱动程序。
                2. 您要检查的元素。应该提供 from 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; 
                    }
                

                【讨论】:

                  【解决方案13】:

                  这对我有用:

                   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']”不存在怎么办?那么将抛出异常,因此 if 条件永远不会计算
                  【解决方案14】:

                  给出我的 sn-p 代码。因此,下面的方法检查页面上是否存在随机 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;
                      }
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    您可以通过在 try catch 语句之前缩短 selenium 超时来使代码运行得更快。

                    我使用下面的代码来检查一个元素是否存在。

                    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 超时保留为默认值,然后使用它。
                    • 自从写下这个答案后,我了解到使用 ExpectedConditions 被认为是更好的形式,但在尝试确定元素是否不存在时,使用 try catch 语句仍然有用。
                    • 我坚持使用旧版本的 selenium,因为我必须测试 IE8。但是我会在可以升级时尝试一下
                    • 每次你的方法都会设置隐式等待超时,但逻辑上我们应该只在初始化驱动对象后设置一次隐式等待,并且超时设置为驱动会话。
                    【解决方案16】:

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

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

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

                    【讨论】:

                      【解决方案17】:

                      我会使用类似的东西(使用 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))
                      

                      【讨论】:

                        【解决方案18】:
                        public boolean isElementDisplayed() {
                                return !driver.findElements(By.xpath("...")).isEmpty();
                            }
                        

                        【讨论】:

                          猜你喜欢
                          • 2021-09-11
                          • 2013-10-30
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-11-11
                          • 2014-01-05
                          • 2021-03-19
                          相关资源
                          最近更新 更多