Selenium wait until document is ready

2019-01-02 19:37发布

Can anyone let me how can I make selenium wait until the time the page loads completely? I want something generic, I know I can configure WebDriverWait and call something like 'find' to make it wait but I don't go that far. I just need to test that the page loads successfully and move on to next page to test.

I found something in .net but couldn't make it work in java ...

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

Any thoughts anyone?

26条回答
若你有天会懂
2楼-- · 2019-01-02 20:11

For the people who need to wait for a specific element to show up. (used c#)

public static void WaitForElement(IWebDriver driver, By element)
{
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
    wait.Until(ExpectedConditions.ElementIsVisible(element));
}

Then if you want to wait for example if an class="error-message" exists in the DOM you simply do:

WaitForElement(driver, By.ClassName("error-message"));

For id, it will then be

WaitForElement(driver, By.Id("yourid"));

查看更多
墨雨无痕
3楼-- · 2019-01-02 20:12
WebDriverWait wait = new WebDriverWait(dr, 30);
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==\"complete\";"));
查看更多
唯独是你
4楼-- · 2019-01-02 20:15

Here's my attempt at a completely generic solution, 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

查看更多
高级女魔头
5楼-- · 2019-01-02 20:16

You can have the thread sleep till the page is reloaded. This is not the best solution, because you need to have an estimate of how long does the page take to load.

driver.get(homeUrl); 
Thread.sleep(5000);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord);
driver.findElement(By.xpath("Your_Xpath_here")).click();
查看更多
回忆,回不去的记忆
6楼-- · 2019-01-02 20:16

I Checked page load complete, work in Selenium 3.14.0

    public static void UntilPageLoadComplete(IWebDriver driver, long timeoutInSeconds)
    {
        Until(driver, (d) =>
        {
            Boolean isPageLoaded = (Boolean)((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete");
            if (!isPageLoaded) Console.WriteLine("Document is loading");
            return isPageLoaded;
        }, timeoutInSeconds);
    }

    public static void Until(IWebDriver driver, Func<IWebDriver, Boolean> waitCondition, long timeoutInSeconds)
    {
        WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
        webDriverWait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        try
        {
            webDriverWait.Until(waitCondition);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
查看更多
后来的你喜欢了谁
7楼-- · 2019-01-02 20:17

This is a working Java version of the example you gave :

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}

Example For c#:

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
  IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
  WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
  wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}
查看更多
登录 后发表回答