简体   繁体   English

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

[英]Test if an element is present using Selenium WebDriver

Is there a way how to test if an element is present?有没有办法测试元素是否存在? Any findElement method would end in an exception, but that is not what I want, because it can be that an element is not present and that is okay.任何findElement方法都会以异常结束,但这不是我想要的,因为元素可能不存在,这没关系。 That is not a fail of the test, so an exception can not be the solution.那不是测试失败,所以异常不能成为解决方案。

I've found this post: Selenium C# WebDriver: Wait until element is present .我找到了这篇文章: Selenium C# WebDriver: Wait until element is present

But this is for C#, and I am not very good at it.但这是针对 C# 的,我不太擅长。 What would the code be in Java? Java 中的代码是什么? I tried it out in Eclipse , but I didn't get it right into Java code.我在Eclipse中尝试过,但我没有把它正确地放入 Java 代码中。

This is the code:这是代码:

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

Use findElements instead of findElement .使用findElements而不是findElement

findElements will return an empty list if no matching elements are found instead of an exception.如果没有找到匹配的元素而不是异常, findElements将返回一个空列表。

To check that an element is present, you could try this要检查元素是否存在,你可以试试这个

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

This will return true if at least one element is found and false if it does not exist.如果找到至少一个元素,则返回 true,如果不存在则返回 false。

The official documentation recommends this method: 官方文档推荐这种方法:

findElement should not be used to look for non-present elements, use findElements(By) and assert zero length response instead. findElement 不应用于查找不存在的元素,而应使用 findElements(By) 并断言零长度响应。

What about a private method that simply looks for the element and determines if it is present like this:一个简单地查找元素并确定它是否存在的私有方法怎么样:

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

This would be quite easy and does the job.这将很容易并且可以完成工作。

Edit: you could even go further and take a By elementLocator as parameter, eliminating problems if you want to find the element by something other than id.编辑:您甚至可以更进一步,将By elementLocator作为参数,如果您想通过 id 以外的其他东西查找元素,则可以消除问题。

I found that this works for Java:我发现这适用于 Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);
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);
}

I had the same issue.我遇到过同样的问题。 For me, depending on a user's permission level, some links, buttons and other elements will not show on the page.对我来说,根据用户的权限级别,某些链接、按钮和其他元素不会显示在页面上。 Part of my suite was testing that the elements that SHOULD be missing, are missing.我的套件的一部分是测试应该丢失的元素是否丢失。 I spent hours trying to figure this out.我花了几个小时试图弄清楚这一点。 I finally found the perfect solution.我终于找到了完美的解决方案。

What this does, is tells the browser to look for any and all elements based specified.它的作用是告诉浏览器查找任何和所有基于指定的元素。 If it results in 0 , that means no elements based on the specification was found.如果结果为0 ,则表示未找到基于规范的元素。 Then i have the code execute an if statement to let me know it was not found.然后我让代码执行一个 if 语句,让我知道它没有找到。

This is in C# , so translations would need to be done to Java .这是在C# ,因此需要对Java进行翻译。 But shouldnt be too hard.但应该不会太难。

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

There's also another path you can take depending on what you need for your test.根据您的测试需要,您还可以采用另一条路径。

The following snippet is checking to see if a very specific element exists on the page.以下代码段用于检查页面上是否存在非常特定的元素。 Depending on the element's existence I have the test execute an if else.根据元素的存在,我让测试执行 if else。

If the element exists and is displayed on the page, I have console.write let me know and move on.如果该元素存在并显示在页面上,我让console.write让我知道并继续。 If the element in question exists, I cannot execute the test I needed, which is the main reasoning behind needing to set this up.如果有问题的元素存在,我将无法执行我需要的测试,这是需要设置它的主要原因。

If the element Does Not exists, and is not displayed on the page.如果该元素不存在,并且未显示在页面上。 I have the else in the if else execute the test.我在 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.
}

I know I'm a little late on the response to the OP.我知道我对 OP 的回应有点晚了。 Hopefully this helps someone!希望这对某人有所帮助!

Try this: Call this method and pass 3 arguments:试试这个:调用这个方法并传递 3 个参数:

  1. WebDriver variable. WebDriver 变量。 // assuming driver_variable as driver. // 假设 driver_variable 作为驱动程序。
  2. The element which you are going to check.您要检查的元素。 Should provide from By method.应该提供 from By 方法。 // ex: By.id("id") // 例如:By.id("id")
  3. Time limit in seconds.以秒为单位的时间限制。

Example: waitForElementPresent(driver, By.id("id"), 10 );示例: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; 
    }

This works for me:这对我有用:

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

You can make the code run faster by shorting the selenium timeout before your try catch statement.您可以通过在 try catch 语句之前缩短 selenium 超时来使代码运行得更快。

I use the following code to check if an element is present.我使用以下代码来检查元素是否存在。

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

Write the following function/methos using Java:使用 Java 编写以下函数/方法:

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

Call the method with appropriate parameter during assertion.在断言期间使用适当的参数调用方法。

if you are using rspec-Webdriver in ruby, you can use this script assuming that an element should really not be present and it is a passed test.如果你在 ruby​​ 中使用 rspec-Webdriver,你可以使用这个脚本,假设一个元素真的不应该存在并且它是一个通过的测试。

First, write this method first from your class RB file首先,首先从您的类 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

Then, on your spec file, call that method.然后,在您的规范文件中,调用该方法。

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

 @Test.element_present?.should == nil

If your the element is NOT present, your spec will pass, but if the element is present , it will throw an error, test failed.如果你的元素不存在,你的规范将通过,但如果元素存在,它会抛出一个错误,测试失败。

Personally, I always go for a mixture of the above answers and create a re-usable static Utility method that uses the size() > 0 suggestion:就我个人而言,我总是混合使用上述答案并创建一个可重用的静态实用程序方法,该方法使用size() > 0建议:

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

This is neat, re-usable, maintainable ... all that good stuff ;-)这是整洁的,可重复使用的,可维护的......所有这些好东西;-)

public boolean isElementDisplayed() {
        return !driver.findElements(By.xpath("...")).isEmpty();
    }

Simplest way I found in Java is:我在 Java 中找到的最简单的方法是:

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

To find a particular Element is present or not, we have to use findElements() method instead of findElement()..要查找特定元素是否存在,我们必须使用 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");

this is worked for me.. suggest me if i am wrong..这对我有用..如果我错了,请建议我..

This should do it:这应该这样做:

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

You can try implicit wait:您可以尝试隐式等待:

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

Or You can try explicit wait one:或者您可以尝试显式等待一:

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

Explicit will check if element is present before some action. Explicit 将在某些操作之前检查元素是否存在。 Implicit wait could be call in every place in the code.隐式等待可以在代码的每个地方调用。 For example after some AJAX actions.例如在一些 AJAX 操作之后。

More you can find at SeleniumHQ page您可以在SeleniumHQ 页面找到更多信息

Giving my snippet of code.给我的代码片段。 So, the below method checks if a random web element ' Create New Application ' button exists on a page or not.因此,下面的方法检查页面上是否存在随机网络元素“创建新应用程序”按钮。 Note that I have used the wait period as 0 seconds.请注意,我使用的等待时间为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;
    }
}

I would use something like (with Scala [the code in old "good" Java 8 may be similar to this]):我会使用类似的东西(使用 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
  }
  ...
}

so then,那么,

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

In 2022 this can now be done without an annoying delay, or affecting your current implicit wait value.在 2022 年,这现在可以在没有烦人的延迟或影响您当前的隐式等待值的情况下完成。

First bump your Selenium driver to latest (currently 4.1.2 ).首先将您的 Selenium 驱动程序升级到最新版本(当前为4.1.2 )。

Then you can use getImplicitWaitTimeout then set timeout to 0 to avoid a wait then restore your previous implicit wait value whatever it was:然后你可以使用getImplicitWaitTimeout然后将超时设置为 0 以避免等待然后恢复你以前的隐式等待值,无论它是什么:

Duration implicitWait = driver.manage().timeouts().getImplicitWaitTimeout();
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(0));
final List<WebElement> signOut = driver.findElements(By.linkText("Sign Out"));
driver.manage().timeouts().implicitlyWait(implicitWait); // Restore implicit wait to previous value

if (!signOut.isEmpty()) {
    ....
}

Try the below code using the isDispplayed() method to verify if the element is present or not:使用isDispplayed()方法尝试以下代码来验证元素是否存在:

WebElement element = driver.findElements(By.xpath(""));
element.isDispplayed();

There could be multiple reasons due to which you might observe exceptions while locating a WebElement using Selenium driver.可能有多种原因导致您在使用 Selenium 驱动程序定位 WebElement 时可能会观察到异常。

I would suggest you to apply the below suggestions for different scenarios:我建议您针对不同的场景应用以下建议:

Scenario 1 : You just want to find out if a certain WebElement is present on the screen or not .场景 1 :您只想了解某个 WebElement是否出现在屏幕上。 For example, the Save button icon will only appear until the form is fully filled and you may want to check if Save button is present or not in your test.例如,“保存”按钮图标只会在表单填满之前出现,您可能想检查测试中是否存在“保存”按钮。

Use the below code -使用以下代码 -

public Boolean isElementLoaded(By locator){
    return !getWebElements(this.driver.findElements(locator), locator).isEmpty();
}

Scenario 2: You want to wait before a WebElement becomes visible in the UI场景 2:您想等待 WebElement 在 UI 中可见

public List<WebElement> waitForElementsToAppear(By locator) {
    return wait.until(visibilityOfAllElementsLocatedBy(by));
}

Scenario 3: Your test is flaky because the WebElement becomes stale sometimes and gets detached from the DOM.场景 3:您的测试不稳定,因为 WebElement 有时会变得陈旧并与 DOM 分离。

protected final List<Class<? extends WebDriverException>> exceptionList =
    List.of(NoSuchWindowException.class,
            NoSuchFrameException.class,
            NoAlertPresentException.class,
            InvalidSelectorException.class,
            ElementNotVisibleException.class,
            ElementNotSelectableException.class,
            TimeoutException.class,
            NoSuchSessionException.class,
            StaleElementReferenceException.class);

    public WebElement reactivateWebElement(By by, WebElement element){
        try {
            wait.ignoreAll(exceptionList)
                    .until(refreshed(visibilityOf(element)));
            logger.info(("Element is available.").concat(BLANK).concat(element.toString()));
        } catch (WebDriverException exception) {
            logger.warn(exception.getMessage());
        } return this.driver.findElement(by);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM