Elininja
Elininja

Reputation: 185

Why does Selenium Webdriver findElements(By.Id) timeout when the element isn't in the DOM?

I am writing a test where I want to verify that an element is NOT present on a page (displayed or otherwise). I've read in various articles (like this one) how to do the element detection with a list that's empty or not. That works just fine for the opposite test that verifies the elements ARE present. However, when the element is not present, I am consistently getting a WebDriverException timeout after 60 secs of spinning: See screenshot here

The element detection function is as such:

public bool isButtonPresent(string buttonType)
    {
        switch (buttonType)
        {
            case "Button 1":
                return !(Driver.FindElements(By.Id("Button 1 ID Here")).Count == 0);
            case "Button 2":
                return !(Driver.FindElements(By.Id("Button 2 ID Here")).Count == 0);
            case "Button 3":
                return !(Driver.FindElements(By.Id("Button 3 ID Here")).Count == 0);
        }
        return false;
    }

Thank you for your time!

Upvotes: 8

Views: 19822

Answers (5)

Sacha Durand
Sacha Durand

Reputation: 590

In javascript, it's :

driver.manage().timeouts().implicitlyWait(10);

Upvotes: 1

Andreas Karz
Andreas Karz

Reputation: 410

Forget the ExpectedConditions and the WebDriverWait -- both don't work really well.

  1. If you have a ImplicitWait, the WebDriverWait is completely ignored. So you can not set the default timeout over ImplicitWait to 10 seconds and then create a WebDriverWait instance with 1 second only to check, if a element is present
  2. WebDriverWait ignores the IgnoreExceptionTypes = WebDriverTimeoutException, so you need allways a try catch

With the following approach you have a simple and comfortable solution that works with a minimum of code:

using System.Linq;

#Decrease the timeout to 1 second
   Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1);

#FindElements get an array and Linq take the first or null
   var result = Driver.FindElements(By.TagName("h7")).FirstOrDefault();

#Increase the timeout to 10 second
   Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

The result will be the desired IWebElement or Null

Unfortunately the getter to get the current value from ImplicitWait is not implemented since 2016. So you can only reset the value to a fixed value and not dynamically read it before.

Upvotes: 2

CSharp
CSharp

Reputation: 1583

Here are the options:
Option 1:

// Specify the amount of time the driver should wait when searching for an element if it is not immediately present. Specify this time to 0 to move ahead if element is not found.
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));  
// InvisibilityOfElementLocated will check that an element is either invisible or not present on the DOM.
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(byLocator));  

With this approach, if your next action is to click on any element, sometimes you will get an error (org.openqa.selenium.WebDriverException: Element is not clickable at point (411, 675)) with Chrome browser. it works fine with Firefox.

Option 2:

// Set the implicit timeout to 0 as we did in option 1
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));  
WebDriverWait wait = new WebDriverWait(Driver.Browser, new TimeSpan(0, 0, 15));
try
{
   wait.Until(FindElement(By));
}
catch(WebDriverException ex) // Catch the WebDriverException here
{
   return;
}  

Here we are making implicit wait to 0 and finding element. if element is is not present it will try for next 15 seconds (you can change this number by your convenience). if there is time out, complete the function.

Option 3:

Sudeepthi has already suggested it.

Drivers._driverInstance.FindElement(by).Displayed;

Upvotes: 7

ddavison
ddavison

Reputation: 29032

another solution would be use an explicit wait. In Java (pseudo-code; you'd have to translate) something like this would work:

wait.until(ExpectedConditions.not(ExpectedConditions.invisibilityOfElementLocated(by)), 10, 1000)

that will wait until the element appears on the page, polling every second for ten seconds.

Upvotes: 0

Sudeepthi
Sudeepthi

Reputation: 494

Will something like this work?

public static bool IsElementPresent(By by)
{
    try
    {
       bool b = Drivers._driverInstance.FindElement(by).Displayed;
       return b;
    }
    catch
    {
       return false;
    }
}

Upvotes: 3

Related Questions