如何在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; } }