【问题标题】:How I can check whether a page is loaded completely or not in web driver?如何在 Web 驱动程序中检查页面是否已完全加载?
【发布时间】:2012-06-15 14:14:21
【问题描述】:

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

我已声明隐式等待 WebDriver。

【问题讨论】:

    标签: jquery selenium webdriver wait


    【解决方案1】:

    Selenium 为您完成。或者至少它尽力而为。有时它不够用,你必须帮助它一点点。通常的解决方案是Implicit Wait,它可以解决大部分问题。

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


    相关问题:Selenium WebDriver : Wait for complex page with JavaScript(JS) to load,在此查看我的回答。

    较短的版本:你永远无法确定。

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

    您可以做的各种事情都在上面的链接下。或者,像 95% 的其他人一样,在需要时使用 Implicit Waitimplicity 和 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));
    

    【讨论】:

    • 感谢 Slanec,我也可以添加显式等待,但我不确定需要更多加载时间的点。是的,你写的大部分应用程序都在不断地拉信息表单服务器。那么在那种情况下我该如何实现 DOM。
    • @Raghubansh 我不知道你刚才说了什么:)。但是,我对答案进行了一些编辑以使其更清楚。如果你有一个具体的问题要解决,就提出一个问题,发表你的努力,我们会看看我们能做些什么:)。
    • 谢谢!请注意,您的示例代码在某一时刻显示 elen 而不是 elem
    • 虽然这是一个老问题,但我应该注意,我的印象是,将焦点更改为 iframe 时,默认情况下不会检查 document.readyState
    • @LetsPlayYahtzee 这可能是真的。老实说,我已经不知道了,我已经 3 年多没有使用 WebDriver 了。我很确定它会在单击和/或获取后检查它。
    【解决方案2】:

    简单的ready2use sn-p,非常适合我

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

    【讨论】:

    • 这里的大多数情况都在等待一个已知元素。但有时您想保护您不知道的页面上的行为。就我而言,javascript 加载缓慢会造成麻烦。因此,当您访问您不知道的页面时,这对我来说是最好的选择。方法确实很强。所以我只是在本地等待时检查了 document.readyState
    • 你有什么观察,里奥?
    • 有些页面在加载元素后会在元素上添加链接(ajax)。所以当页面开始加载的时候,出现的元素没有正确的链接,驱动就会驱动不正确。所以对我来说,最好的选择是在点击某个链接之前等待文档就绪状态 public void EsperaPagina(IWebDriver driver) { WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20.0)); wait.Until(delegate (IWebDriver d){return (Boolean)((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"); });}
    • 这个答案只是复制了 selenium 的内部功能
    【解决方案3】:

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

    与检查元素可见性相比,此方法的优点是您可以在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");
    });
    

    【讨论】:

    • 那仍然会有竞争条件。您在页面 A(已设置令牌变量)上,单击指向页面 B 的链接,然后立即告诉它等待设置变量(假设在页面 B),但如果请求需要几个几秒钟后开始,它会找到现有的页面 A 变量并愉快地继续。
    • 啊,当时我正在使用单页应用程序。所以这个问题从未出现过。
    【解决方案4】:

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

    该方法是作为扩展方法使用的,说的简单点;在这种情况下,您可以向对象 IWebDriver 添加更多功能(方法)。重要的是您必须在参数中定义:'this' 才能使用它。

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

    【讨论】:

    • 感谢您在这里发帖,尽管这是一个旧线程。我在 EC2 上启动 Selenium 测试时遇到了疯狂的问题,而 jquery 部分解决了我的问题。谢谢!
    【解决方案5】:

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

    希望这会有所帮助!它正在实施阶段,对我来说也是......

    【讨论】:

      【解决方案6】:

      这是我将如何解决它,使用代码 sn-p 给你一个基本的想法:

      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") ) );
          }
      ....
      

      【讨论】:

        【解决方案7】:

        下面是我的 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】:

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

          【讨论】:

            【解决方案9】:

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

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

            【讨论】:

              【解决方案10】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-10-28
                • 1970-01-01
                相关资源
                最近更新 更多