Recently I wrote some SpecFlow / Selenium based automated front end tests for a client. I would repeatedly run into situations where the test framework would try to execute the test steps faster than the page under test would load. This caused a lot of random test failures. I spent some time searching the internet to determine if this was a common issue and if there was any sort of solution for it. There were a lot of folks that wrote their own custom wait solutions to try and address this.
As it turns out, Selenium actually has some built in functionality that is designed to try and fix this. In the Selenium documentation, you’ll find the idea of both implicit and explicit waits. An explicit wait delays execution of code and waits for a certain condition to be met. The explicit wait that most people are familiar with is the generic thread.sleep function. I am generally not a fan of this because you’re guessing how long the sleep should last in order to wait for the page to load or the code to complete. A better way to use explicit waits is the WebDriverWait along with Expected condition.
For example (from the Selenium documentation):
WebDriver driver = new FirefoxDriver(); driver.get("http://somedomain/url_that_delays_loading"); WebElement myDynamicElement = (new WebDriverWait(driver, 10)) .until( ExpectedConditions .presenceOfElementLocated(By.id("myDynamicElement")));
In the snippet above, the test will wait until the myDynamicElement has been loaded and is available. In the event that it is not available in ten seconds, a timeout exception will be thrown. This is based on the value passed into the WebDriverWait. We can take a look at this and modify it for an actual site as well. The following snippet of code uses an explicit wait in order to wait for the Edit This Page link at the top of the homepage for Selenium:
WebDriver driver = new FirefoxDriver(); driver.get("http://seleniumhq.org/"); WebElement EditThisPage = (new WebDriverWait(driver, 10)) .until( ExpectedConditions .presenceOfElementLocated(By.linkText("edit this page")));
In addition to explicit waits, there are also implicit waits. An implicit wait looks at the DOM (Document Object Model – basically a list of objects contained in an HTML file or website) for a period of time in order to try and find an element if they are not currently available. The biggest difference between implicit and explicit wait is that once the amount of time is set for an implicit wait, it will remain that value for the entire life of the WebDriver instance. An example of an implicit wait (from the selenium documentation):
WebDriver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("http://somedomain/url_that_delays_loading"); WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));
Going back to the selenium home page, here is another example of an implicit wait:
WebDriver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("http://www.seleniumhq.org/"); WebElement EditThisPage = driver.findElement(By.linkText("edit this page"));
Once I knew that explicit and implicit waits were available to me, I was able to use explicit waits to make sure the objects I was looking for were available, and I was encountering less random test failures. If you’re having issues with your tests running away while your page loads, try an implicit or explicit wait and see if that resolves your issues.