0

I am trying to use the Selenium WebDriverWait type to wait for the page to fully load before checking if an element exists. I tried doing this two different ways.

The First Method uses IgnoreExceptionTypes, and then calls FindElement inside the Until Method. This immediately throws the NoSuchElementException without waiting. I expected this continue to try to find the element until the timeout, while ignoring the NoSuchElementException. It does not appear to work this way. Why doesn't Method1 work?

The Second Method uses ExpectedConditions.ElementExists, and seems to wait correctly.

driver.Navigate().GoToUrl("http://www.google.com");
var myId = "myId";

//Method 1
var wait1 = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait1.IgnoreExceptionTypes(typeof(NoSuchElementException));

//Does not wait. Immediately throws NoSuchElementException
var result1 = wait1.Until(x => x.FindElement(By.Id(myId)));

//Method 2    - works as expected
var wait2= new WebDriverWait(driver,TimeSpan.FromSeconds(10))
    .Until(ExpectedConditions.ElementExists(By.Id(myId)));
2
  • Are you using page object model? Commented Nov 7, 2017 at 15:23
  • I don't think so..my question has all the code except for creating the driver Commented Nov 7, 2017 at 15:32

1 Answer 1

1

Answering the newly rephrased question...

So I do this all the time. I use the page object model to write automation so this works well for that but you can still use it even if you aren't using the page object model.

The basic concept is this... you find an element that loads last and wait for that element. At that point, you know that the page is done loading and your script can continue without fear of interacting with some element on the page that hasn't finished loading.

The caveat... how in the world do I know which element is the last to load? I have no idea. You basically make a guess (hopefully educated guess) and use it until it fails. If your page isn't terribly dynamic, then just choose about any element. If there's a part of the page that loads late, choose an element inside that portion of the page.

Here's how this typically goes for me. I write a page object for some page. I pick a unique element on the page and declare that as By waitForLocator. Now when I want to wait for the page to finish loading I call

By waitForLocator = By.Id("myId");
new WebDriverWait(Driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementIsVisible(waitForLocator));

Now I'm (fairly) confident that the page is done loading and I go about writing methods for the page object and so on. I write a script that consumes that page object and interact with the page according to my test case and then I run the script. Hopefully I picked my waitForLocator well. If I haven't, at some point during the script run I'll get some exception because some element wasn't fully loaded (it loaded after the element I picked). So, I change the waitForElement to the element that I just interacted with that threw the exception and now I should have a better guess at the last loading element. You basically repeat this process until you get no more exceptions.

You might say, this is a very haphazard way to do this. It really seems more haphazard than it really is. If you know your site and your pages, you will make a pretty good first guess. It's pretty rare that I have to change that guess once and it's REALLY rare that I have to change it more than once. That said, changing it is really easy. You already have the locator for the element that threw the exception, you just paste it into the declaration for waitForLocator and you're done.

So one exception that you might run into is if you've properly chosen your waitForLocator and after the page has loaded, you click on some element on the page which dynamically loads some other portion of the page. This scenario is beyond the scope of waiting for the page to load. In this case, you would have to build in another wait that waits for the newly loading portion of the page to finish loading after a click is performed. It will not affect the page loading mechanism.


Additional comments

After going back and reading your question, here's some additional info that will make your life easier.

Your original question had a method that I've simplified/modified below to demonstrate this principle

public void ClickElementById(RemoteWebDriver driver, string id)
{
    driver.FindElement(By.Id(id)).Click();
}

The way this method is written, you forced yourself to create a method for each locator type, ID, name, CSS selector, XPath, etc. Rather than pass in a string, pass in a By locator.

public void ClickElement(RemoteWebDriver driver, By locator)
{
    driver.FindElement(locator).Click();
}

Now with this new method, it's completely flexible. You can pass in any locator type and it will work. To call it you use something like

ClickElement(driver, By.Id("someId"));
Sign up to request clarification or add additional context in comments.

2 Comments

I'm confused. Your method that you posted has driver and id as parameters but you are talking about a custom wait time and an existing element. You probably need to clarify your question as to what you are actually doing since it seems to be different than the question you are asking here.
Updated my answer based on the new info

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.