How do you make Selenium 2.0 wait for the page to load?
30 Answers
Use class WebDriverWait
Also see here
You can expect to show some element. something like in C#:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
If you set the implicit wait of the driver, then call the findElement
method on an element you expect to be on the loaded page, the WebDriver will poll for that element until it finds the element or reaches the time out value.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
source: implicit-waits
You may remove the System.out
line. It is added for debug purposes.
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
All of these solutions are OK for specific cases, but they suffer from at least one of a couple of possible problems:
They are not generic enough -- they want you to know, ahead of time, that some specific condition will be true of the page you are going to (eg some element will be displayed)
They are open to a race condition where you use an element that is actually present on the old page as well as the new page.
Here's my attempt at a generic solution that avoids this problem (in Python):
First, a generic "wait" function (use a WebDriverWait if you like, I find them ugly):
def wait_for(condition_function):
start_time = time.time()
while time.time() < start_time + 3:
if condition_function():
return True
else:
time.sleep(0.1)
raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
Next, the solution relies on the fact that selenium records an (internal) id-number for all elements on a page, including the top-level <html>
element. When a page refreshes or loads, it gets a new html element with a new ID.
So, assuming you want to click on a link with text "my link" for example:
old_page = browser.find_element_by_tag_name('html')
browser.find_element_by_link_text('my link').click()
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
For more Pythonic, reusable, generic helper, you can make a context manager:
from contextlib import contextmanager
@contextmanager
def wait_for_page_load(browser):
old_page = browser.find_element_by_tag_name('html')
yield
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
And then you can use it on pretty much any selenium interaction:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
I reckon that's bulletproof! What do you think?
More info in a blog post about it here
You can also use the class: ExpectedConditions
to explicitly wait for an element to show up on the webpage before you can take any action further actions
You can use the ExpectedConditions
class to determine if an element is visible:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
See ExpectedConditions class Javadoc
for list of all conditions you are able to check.
This seems to be a serious limitation of WebDriver. Obviously waiting for an element will not imply the page being loaded, in particular the DOM can be fully build (onready state) whereby JS is still executing and CSS and images are still loading.
I believe the simplest solution is to set a JS variable upon the onload event after everything is initialized and check and wait for this JS variable in Selenium.
Here is a Java 8 version of the currently most upvoted answer:
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Where myDriver
is a WebDriver
object (declared earlier).
Note: Be aware that this method (document.readyState
) only checks the DOM.
If you want to wait for a specific element to load, you can use the isDisplayed()
method on a RenderedWebElement
:
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(Example from The 5 Minute Getting Started Guide)
Explicitly wait or conditional wait in this wait until given this condition.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
This will wait for every web element for 60 seconds.
Use implicitly wait for wait of every element on page till that given time.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
This will wait for every web element for 60 seconds.
Man all these answers require too much code. This should be a simple thing as its pretty common.
Why not just inject some simple Javascript with the webdriver and check. This is the method I use in my webscraper class. The Javascript is pretty basic even if you don't know it.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
I'm surprised that predicates weren't the first choice as you typically know what element(s) you will next interact with on the page you're waiting to load. My approach has always been to build out predicates/functions like waitForElementByID(String id)
and waitForElemetVisibleByClass(String className)
, etc. and then use and reuse these wherever I need them, be it for a page load or page content change I'm waiting on.
For example,
In my test class:
driverWait.until(textIsPresent("expectedText");
In my test class parent:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Though this seems like a lot, it takes care of checking repeatedly for you and the interval for how often to check can be set along with the ultimate wait time before timing out. Also, you will reuse such methods.
In this example, the parent class defined and initiated the WebDriver driver
and the WebDriverWait driverWait
.
I hope this helps.
Use implicitly wait for wait of every element on page till given time.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
this wait for every element on page for 30 sec.
Another wait is Explicitly wait or conditional wait in this wait until given condition.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
In id give static element id which is diffidently display on the page, as soon as page is load.
The best way to wait for page loads when using the Java bindings for WebDriver is to use the Page Object design pattern with PageFactory. This allows you to utilize the AjaxElementLocatorFactory
which to put it simply acts as a global wait for all of your elements. It has limitations on elements such as drop-boxes or complex javascript transitions but it will drastically reduce the amount of code needed and speed up test times. A good example can be found in this blogpost. Basic understanding of Core Java is assumed.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Call below Function in your script , this will wait till page is not loaded using javascript
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
NodeJS Solution:
In Nodejs you can get it via promises...
If you write this code, you can be sure that the page is fully loaded when you get to the then...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
If you write this code, you will navigate, and selenium will wait 3 seconds...
driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...
From Selenium Documentation (Nodejs):
this.get( url ) → Thenable<undefined>
Schedules a command to navigate to the given URL.
Returns a promise that will be resolved when the document has finished loading.
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
You can change from the document to an element, in the case of where only part of a document is being changed.
This technique was inspired by the answer from sincebasic.
SeleniumWaiter:
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
And to you use it:
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
The best way I've seen is to utilize the stalenessOf
ExpectedCondition, to wait for the old page to become stale.
Example:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
It'll wait for ten seconds for the old HTML tag to become stale, and then throw an exception if it doesn't happen.
I use node + selenium-webdriver(which version is 3.5.0 now). what I do for this is:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
You can use wait. there are basically 2 types of wait in selenium
- Implicit wait
- Explicit wait
- Implicit wait
This is very simple please see syntax below:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Explicit wait
Explicitly wait or conditional wait in this wait until given condition is occurred.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
You can use other properties like visblityOf()
, visblityOfElement()
If someone uses selenide:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
More Conditions can be found here: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
In my case , I used the following to know the page load status. In our application loading gif(s) are present and, I listen to them as follows to eliminate unwanted wait time in the script.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
Where the xpath locates the gif in the HTML DOM. After this, You may also implement your action methods Click.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
You can explicitly wait for an element to show up on the webpage before you can take any action (like element.click()
):
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>() {
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}
}
);
This is what I used for a similar scenario and it works fine.
How to get Selenium to wait for page load after a click provides the following interesting approach:
- Store a reference to a
WebElement
from the old page. - Click the link.
- Keep on invoking operations on the
WebElement
untilStaleElementReferenceException
is thrown.
Sample code:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});