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

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

我已经声明了WebDriver的隐式等待。

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

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


相关问题: Selenium WebDriver:等待加载JavaScript(JS)的复杂页面 ,请在那里查看我的答案。

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

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

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

例如,点击后,页面上的某些元素应该可见,您需要等待它:

 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)); 

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

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

MyWebPage.html

 ... All my page content ...  

在您的测试中(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(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"); }); 

简单的ready2use片段,非常适合我

 static void waitForPageLoad(WebDriver wdriver) { WebDriverWait wait = new WebDriverWait(wdriver, 60); Predicate pageLoaded = new Predicate() { @Override public boolean apply(WebDriver input) { return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete"); } }; wait.until(pageLoaded); } 

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

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

超时变量是webdriver等待的秒数(如果页面没有响应)。 使用’Selenium’和’Selenium.Support.UI’命名空间,可以执行一段返回布尔值的javascript,无论文档是否已准备好(完成)以及是否加载了jQuery。 如果页面没有jQuery,那么该方法将抛出exception。 error handling会“捕获”此exception。 在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 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"); } } 

最近,当我处理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(); } } 

希望这可以帮助!! 它正处于实施阶段,对我来说也是……

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

 public class IFrame1 extends LoadableComponent { 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 wait = new FluentWait( 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") ) ); } .... 

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

下面是我的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 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 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; } }