如何在Web驱动程序中检查页面是否完全加载?

时间:2012-06-12 16:43:44

标签: jquery selenium webdriver wait

我正在编写一些Java Webdriver代码来自动化我的应用程序。如何正确检查页面是否已加载?该应用程序也有一些Ajax调用。

我已声明隐含等待WebDriver。

10 个答案:

答案 0 :(得分:34)

Selenium为你做到了。或者至少它会尽力而为。有时它不足,你必须帮助它一点点。通常的解决方案是Implicit Wait,它解决了大部分问题。

如果您真的知道自己在做什么,以及为什么要这样做,那么可以尝试编写一个通用方法来检查页面是否已完全加载。但是,对于每个网络和每种情况都无法做到这一点。


相关问题:Selenium WebDriver : Wait for complex page with JavaScript(JS) to load,请参阅我的答案。

更短的版本:你永远不会确定。

“正常”负载很容易 - document.readyState。当然,这个是由Selenium实现的。有问题的是异步请求,AJAX,因为你永远无法判断它是否为好。今天的大多数网页都有永久运行的脚本,并且一直在轮询服务器。

您可以做的各种事情都在上面的链接之下。或者,与95%的其他人一样,在需要时使用Implicit Wait隐含和Explicit Wait + ExpectedConditions

E.g。点击后,页面上的某些元素应该可见,您需要等待它:

WebDriverWait wait = new WebDriverWait(driver, 10);  // you can reuse this one

WebElement elem = driver.findElement(By.id("myInvisibleElement"));
elem.click();
wait.until(ExpectedConditions.visibilityOf(elem));

答案 1 :(得分:3)

您可以在WepPage中设置一个JavaScript变量,该变量在加载后设置。你可以把它放在任何地方,但是如果你使用jQuery,$(document).onReady并不是一个糟糕的起点。如果没有,那么您可以将其放在页面底部的<script>标记中。

与检查元素可见性相反,此方法的优点是您在wait语句执行后知道页面的确切状态。

MyWebPage.html

... All my page content ...
<script> window.TestReady = true; </script></body></html>

在你的测试中(C#例子):

// The timespan determines how long to wait for any 'condition' to return a value
// If it is exceeded an exception is thrown.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5.0));

// Set the 'condition' as an anonymous function returning a boolean
wait.Until<Boolean>(delegate(IWebDriver d)
{
    // Check if our global variable is initialized by running a little JS
    return (Boolean)((IJavaScriptExecutor)d).ExecuteScript("return typeof(window.TestReady) !== 'undefined' && window.TestReady === true");
});

答案 2 :(得分:2)

简单的 ready2use 代码段,非常适合我

static void waitForPageLoad(WebDriver wdriver) {
    WebDriverWait wait = new WebDriverWait(wdriver, 60);

    Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver input) {
            return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
        }

    };
    wait.until(pageLoaded);
}

答案 3 :(得分:1)

我知道这篇文章很老了。但是从上面收集了所有代码后,我做了一个很好的方法(解决方案)来处理ajax运行和常规页面。该代码仅适用于C#(因为Selenium绝对是最适合C#Visual Studio的一年后)。

该方法用作扩展方法,这意味着简单;你可以在这种情况下向对象IWebDriver添加更多功能(方法)。重要的是你必须定义:&#39;这个&#39;在参数中使用它。

超时变量是webdriver等待的秒数(如果页面没有响应)。使用&#39; Selenium&#39;和&#39; Selenium.Support.UI&#39;命名空间可以执行一段返回布尔值的javascript,无论文档是否已准备好(完成)以及是否加载了jQuery。如果页面没有jQuery,那么该方法将抛出异常。这个例外被抓住了#39;通过错误处理。在catch状态下,只检查文档的就绪状态,而不检查jQuery。

public static void WaitUntilDocumentIsReady(this IWebDriver driver, int timeoutInSeconds) {
    var javaScriptExecutor = driver as IJavaScriptExecutor;
    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));

    try {
        Func<IWebDriver, bool> readyCondition = webDriver => (bool)javaScriptExecutor.ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
        wait.Until(readyCondition);
    } catch(InvalidOperationException) {
        wait.Until(wd => javaScriptExecutor.ExecuteScript("return document.readyState").ToString() == "complete");
    }
}

答案 4 :(得分:0)

最近,当我处理AJAX应用程序/ RIA时,我遇到了同样的问题!我使用隐式等待,时间约为90秒。它等待,直到元素可用...所以,我们可以做的是确保该页面完全加载,

添加一个布尔语句,检查条件(元素的特定部分)是否存在并将其分配给变量,检查条件,只有当条件为真时,“执行必要的操作!”。 ..通过这种方式,我发现,两种等待都可以使用......

前:

@Before

{ implicit wait statement}

@Test

{

boolean tr1=Driver.findElement(By.xpath("xx")).isEnabled/isDisplayed;

if (tr1==true && ____)//as many conditions, to make sure, the page is loaded

{

//do the necessary set of actions...
driver.findElement(By.xpath("yy")).click();

}

}

希望这有帮助!!它也处于实施阶段,对我来说也是......

答案 5 :(得分:0)

以下是我将如何修复它,使用代码片段为您提供一个基本想法:

public class IFrame1 extends LoadableComponent<IFrame1> {

    private RemoteWebDriver driver;

    @FindBy(id = "iFrame1TextFieldTestInputControlID" ) public WebElement iFrame1TextFieldInput;
    @FindBy(id = "iFrame1TextFieldTestProcessButtonID" ) public WebElement copyButton;

    public IFrame1( RemoteWebDriver drv ) {
        super();
        this.driver = drv;
        this.driver.switchTo().defaultContent();
        waitTimer(1, 1000);
        this.driver.switchTo().frame("BodyFrame1");
        LOGGER.info("IFrame1 constructor...");
    }

    @Override
    protected void isLoaded() throws Error {        
        LOGGER.info("IFrame1.isLoaded()...");
        PageFactory.initElements( driver, this );
        try {
            assertTrue( "Page visible title is not yet available.", 
                    driver.findElementByCssSelector("body form#webDriverUnitiFrame1TestFormID h1")
                    .getText().equals("iFrame1 Test") );
        } catch ( NoSuchElementException e) {
            LOGGER.info("No such element." );
            assertTrue("No such element.", false);
        }
    }

    /**
     * Method: load
     * Overidden method from the LoadableComponent class.
     * @return  void
     * @throws  null
     */
    @Override
    protected void load() {
        LOGGER.info("IFrame1.load()...");
        Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring( NoSuchElementException.class ) 
                .ignoring( StaleElementReferenceException.class ) ;
        wait.until( ExpectedConditions.presenceOfElementLocated( 
                By.cssSelector("body form#webDriverUnitiFrame1TestFormID h1") ) );
    }
....

答案 6 :(得分:0)

您可以截取屏幕截图并将呈现的页面保存在某个位置,如果页面完全加载而没有损坏的图像,您可以检查屏幕截图

答案 7 :(得分:0)

以下是我的BasePageObject类中的等待代码:

public void waitForPageLoadAndTitleContains(int timeout, String pageTitle) {
    WebDriverWait wait = new WebDriverWait(driver, timeout, 1000);
    wait.until(ExpectedConditions.titleContains(pageTitle));
}

public void waitForElementPresence(By locator, int seconds) {
    WebDriverWait wait = new WebDriverWait(driver, seconds);
    wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}

public void jsWaitForPageToLoad(int timeOutInSeconds) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    String jsCommand = "return document.readyState";

    // Validate readyState before doing any waits
    if (js.executeScript(jsCommand).toString().equals("complete")) {
        return;
    }

    for (int i = 0; i < timeOutInSeconds; i++) {
        TimeManager.waitInSeconds(3);
        if (js.executeScript(jsCommand).toString().equals("complete")) {
            break;
        }
    }
}

   /**
     * Looks for a visible OR invisible element via the provided locator for up
     * to maxWaitTime. Returns as soon as the element is found.
     *
     * @param byLocator
     * @param maxWaitTime - In seconds
     * @return
     *
     */
    public WebElement findElementThatIsPresent(final By byLocator, int maxWaitTime) {
        if (driver == null) {
            nullDriverNullPointerExeption();
        }
        FluentWait<WebDriver> wait = new FluentWait<>(driver).withTimeout(maxWaitTime, java.util.concurrent.TimeUnit.SECONDS)
                .pollingEvery(200, java.util.concurrent.TimeUnit.MILLISECONDS);

        try {
            return wait.until((WebDriver webDriver) -> {
                List<WebElement> elems = driver.findElements(byLocator);
                if (elems.size() > 0) {
                    return elems.get(0);
                } else {
                    return null;
                }
            });
        } catch (Exception e) {
            return null;
        }
    }

支持方法:

     /**
     * Gets locator.
     *
     * @param fieldName
     * @return
     */
    public By getBy(String fieldName) {
        try {
            return new Annotations(this.getClass().getDeclaredField(fieldName)).buildBy();
        } catch (NoSuchFieldException e) {
            return null;
        }
    }

答案 8 :(得分:0)

您可以使用driver.getPageSource()获得网站的HTML。如果html在给定的时间间隔内没有变化,则表示页面已完成加载。一两秒钟就足够了。如果您想加快速度,可以只比较两个html的长度。如果它们的长度相等,则html应相等,这意味着页面已完全加载。 JavaScript解决方案不适用于我。

答案 9 :(得分:0)

解决方案是使用隐式等待,它将解决您的页面加载问题。

WebDriverWait waitForElement = new WebDriverWait(driver, 15);
WebElement element = driver.findElement(By.id("myElement"));
element.click(); 
wait.until(ExpectedConditions.visibilityOf(element));