简体   繁体   English

Selenium WebDriver:等待带有 JavaScript 的复杂页面加载

[英]Selenium WebDriver: Wait for complex page with JavaScript to load

I have a web application to test with Selenium. There is a lot of JavaScript running on page load.我有一个 web 应用程序要用 Selenium 进行测试。页面加载时有很多 JavaScript 正在运行。
This JavaScript code is not so well written but I can't change anything.这段 JavaScript 代码写得不太好,但我无法更改任何内容。 So waiting for an element to appear in the DOM with findElement() method is not an option.因此,使用findElement()方法等待元素出现在 DOM 中不是一种选择。
I want to create a generic function in Java to wait for a page to load, a possible solution would be:我想在 Java 中创建一个通用的 function 来等待页面加载,一个可能的解决方案是:

  • run a JavaScript script form WebDriver and store the result of document.body.innerHTML in a string variable body .从 WebDriver 运行 JavaScript 脚本并将document.body.innerHTML的结果存储在字符串变量body中。
  • compare the body variable to the previous version of body .body变量与以前版本的body进行比较。 if they are the same then set increment a counter notChangedCount otherwise set notChangedCount to zero.如果它们相同则设置递增计数器notChangedCount否则将notChangedCount设置为零。
  • wait for a litte time (50 ms for example).稍等片刻(例如 50 毫秒)。
  • if the page has not changed for some time (500 ms for example) so notChangedCount >= 10 then exit the loop otherwise loop to the first step.如果页面在一段时间内没有改变(例如 500 毫秒),那么notChangedCount >= 10然后退出循环,否则循环到第一步。

Do you think it's a valid solution?你认为这是一个有效的解决方案吗?

If anyone actually knew a general and always-applicable answer, it would have been implemented everywhere ages ago and would make our lives SO much easier.如果有人真的知道一个通​​用且始终适用的答案,那么很久以前它就会在任何地方实施,并且会让我们的生活变得更加轻松。

There are many things you can do, but every single one of them has a problem:你可以做很多事情,但每一件事都有一个问题:

  1. As Ashwin Prabhu said, if you know the script well, you can observe its behaviour and track some of its variables on window or document etc. This solution, however, is not for everyone and can be used only by you and only on a limited set of pages.正如 Ashwin Prabhu 所说,如果你很了解这个脚本,你可以观察它的行为并在windowdocument等上跟踪它的一些变量。但是,这个解决方案并不适合所有人,只能由你使用,并且只能在有限的情况下使用页集。

  2. Your solution by observing the HTML code and whether it has or hasn't been changed for some time is not bad (also, there is a method to get the original and not-edited HTML directly by WebDriver ), but:通过观察 HTML 代码以及它是否在一段时间内没有更改,您的解决方案还不错(还有一种方法可以通过WebDriver直接获取原始且未编辑的 HTML),但是:

    • It takes a long time to actually assert a page and could prolong the test significantly.实际断言页面需要很长时间,并且可能会显着延长测试时间。
    • You never know what the right interval is.你永远不知道什么是正确的间隔。 The script might be downloading something big that takes more than 500 ms.该脚本可能正在下载需要超过 500 毫秒的大文件。 There are several scripts on our company's internal page that take several seconds in IE.我们公司的内部页面上有几个脚本在IE中需要几秒钟。 Your computer may be temporarily short on resources - say that an antivirus will make your CPU work fully, then 500 ms may be too short even for a noncomplex scripts.您的计算机可能暂时缺乏资源 - 假设防病毒软件将使您的 CPU 充分工作,那么即使对于不复杂的脚本,500 毫秒也可能太短了。
    • Some scripts are never done.有些脚本永远不会完成。 They call themselves with some delay ( setTimeout() ) and work again and again and could possibly change the HTML every time they run.他们以一些延迟调用自己( setTimeout() )并一次又一次地工作,并且每次运行时都可能更改 HTML。 Seriously, every "Web 2.0" page does it.说真的,每个“Web 2.0”页面都这样做。 Even Stack Overflow.甚至堆栈溢出。 You could overwrite the most common methods used and consider the scripts that use them as completed, but ... you can't be sure.您可以覆盖最常用的方法并将使用它们的脚本视为已完成,但是……您不能确定。
    • What if the script does something other than changing the HTML?如果脚本除了更改 HTML 之外还执行其他操作怎么办? It could do thousands of things, not just some innerHTML fun.它可以做成千上万的事情,而不仅仅是一些innerHTML乐趣。
  3. There are tools to help you on this.有一些工具可以帮助您解决这个问题。 Namely Progress Listeners together with nsIWebProgressListener and some others.Progress ListenersnsIWebProgressListener和其他一些。 The browser support for this, however, is horrible.然而,浏览器对此的支持非常糟糕。 Firefox began to try to support it from FF4 onwards (still evolving), IE has basic support in IE9. Firefox 从 FF4 开始尝试支持它(仍在发展中),IE 在 IE9 中有基本支持。

And I guess I could come up with another flawed solution soon.我想我很快就会想出另一个有缺陷的解决方案。 The fact is - there's no definite answer on when to say "now the page is complete" because of the everlasting scripts doing their work.事实是 - 关于何时说“现在页面已完成”没有明确的答案,因为永恒的脚本在做他们的工作。 Pick the one that serves you best, but beware of its shortcomings.选择最适合您的那个,但要注意它的缺点。

Thanks Ashwin !谢谢阿什温!

In my case I should need wait for a jquery plugin execution in some element.. specifically "qtip"在我的情况下,我应该等待某个元素中的 jquery 插件执行..特别是“qtip”

based in your hint, it worked perfectly for me :根据您的提示,它对我来说非常有效:

wait.until( new Predicate<WebDriver>() {
            public boolean apply(WebDriver driver) {
                return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
            }
        }
    );

Note: I'm using Webdriver 2注意:我使用的是 Webdriver 2

You need to wait for Javascript and jQuery to finish loading.你需要等待Javascript和jQuery来完成加载。 Execute Javascript to check if jQuery.active is 0 and document.readyState is complete , which means the JS and jQuery load is complete.执行JavaScript,以检查是否jQuery.active0document.readyStatecomplete的,这意味着所述JS和jQuery加载完成。

public boolean waitForJStoLoad() {

    WebDriverWait wait = new WebDriverWait(driver, 30);

    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
          return ((Long)executeJavaScript("return jQuery.active") == 0);
        }
        catch (Exception e) {
          return true;
        }
      }
    };

    // wait for Javascript to load
    ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        return executeJavaScript("return document.readyState")
            .toString().equals("complete");
      }
    };

  return wait.until(jQueryLoad) && wait.until(jsLoad);
}

Does the JS library define/initialize any well known variable on the window? JS 库是否在窗口上定义/初始化了任何众所周知的变量?

If so you could wait for the variable to appear.如果是这样你可以等待变量出现。 You can use您可以使用

((JavascriptExecutor)driver).executeScript(String script, Object... args)

to test for this condition (something like: window.SomeClass && window.SomeClass.variable != null ) and return a boolean true / false .以测试这种情况(是这样的: window.SomeClass && window.SomeClass.variable != null ),并返回一个布尔true / false

Wrap this in a WebDriverWait , and wait until the script returns true .在包装这个WebDriverWait ,并等待脚本返回true

If all you need to do is wait for the html on the page to become stable before trying to interact with elements, you can poll the DOM periodically and compare the results, if the DOMs are the same within the given poll time, you're golden.如果您需要做的就是在尝试与元素交互之前等待页面上的 html 变得稳定,您可以定期轮询 DOM 并比较结果,如果 DOM 在给定的轮询时间内相同,则您金的。 Something like this where you pass in the maximum wait time and the time between page polls before comparing.类似这样的事情,您可以在比较之前传入最大等待时间和页面轮询之间的时间。 Simple and effective.简单有效。

public void waitForJavascript(int maxWaitMillis, int pollDelimiter) {
    double startTime = System.currentTimeMillis();
    while (System.currentTimeMillis() < startTime + maxWaitMillis) {
        String prevState = webDriver.getPageSource();
        Thread.sleep(pollDelimiter); // <-- would need to wrap in a try catch
        if (prevState.equals(webDriver.getPageSource())) {
            return;
        }
    }
}

I had a same issue.我有同样的问题。 This solution works for me from WebDriverDoku:这个解决方案适用于 WebDriverDoku:

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp

The below code works perfectly in my case - my page contains complex java scripts以下代码在我的情况下完美运行 - 我的页面包含复杂的 java 脚本

public void checkPageIsReady() {

  JavascriptExecutor js = (JavascriptExecutor)driver;


  //Initially bellow given if condition will check ready state of page.
  if (js.executeScript("return document.readyState").toString().equals("complete")){ 
   System.out.println("Page Is loaded.");
   return; 
  } 

  //This loop will rotate for 25 times to check If page Is ready after every 1 second.
  //You can replace your value with 25 If you wants to Increase or decrease wait time.
  for (int i=0; i<25; i++){ 
   try {
    Thread.sleep(1000);
    }catch (InterruptedException e) {} 
   //To check page ready state.
   if (js.executeScript("return document.readyState").toString().equals("complete")){ 
    break; 
   }   
  }
 }

Source - How To Wait For Page To Load/Ready In Selenium WebDriver源 - 如何在 Selenium WebDriver 中等待页面加载/就绪

Two conditions can be used to check if the page is loaded before finding any element on the page:在找到页面上的任何元素之前,可以使用两个条件来检查页面是否已加载:

WebDriverWait wait = new WebDriverWait(driver, 50);

Using below readyState will wait till page load使用下面的 readyState 将等到页面加载

wait.until((ExpectedCondition<Boolean>) wd ->
   ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));

Below JQuery will wait till data has not been loaded下面 JQuery 将等待数据尚未加载

  int count =0;
            if((Boolean) executor.executeScript("return window.jQuery != undefined")){
                while(!(Boolean) executor.executeScript("return jQuery.active == 0")){
                    Thread.sleep(4000);
                    if(count>4)
                        break;
                    count++;
                }
            }

After these JavaScriptCode try to findOut webElement.在这些 JavaScriptCode 之后尝试找出 webElement。

WebElement we = wait.until(ExpectedConditions.presenceOfElementLocated(by));

I asked my developers to create a JavaScript variable "isProcessing" that I can access (in the "ae" object) that they set when things start running and clear when things are done.我要求我的开发人员创建一个我可以访问的 JavaScript 变量“isProcessing”(在“ae”对象中),他们在事情开始运行时设置并在事情完成时清除。 I then run it in an accumulator that checks it every 100 ms until it gets five in a row for a total of 500 ms without any changes.然后我在一个累加器中运行它,每 100 毫秒检查一次,直到它连续 5 次,总共 500 毫秒没有任何变化。 If 30 seconds pass, I throw an exception because something should have happened by then.如果 30 秒过去了,我会抛出一个异常,因为那时应该发生了一些事情。 This is in C#.这是在 C# 中。

public static void WaitForDocumentReady(this IWebDriver driver)
{
    Console.WriteLine("Waiting for five instances of document.readyState returning 'complete' at 100ms intervals.");
    IJavaScriptExecutor jse = (IJavaScriptExecutor)driver;
    int i = 0; // Count of (document.readyState === complete) && (ae.isProcessing === false)
    int j = 0; // Count of iterations in the while() loop.
    int k = 0; // Count of times i was reset to 0.
    bool readyState = false;
    while (i < 5)
    {
        System.Threading.Thread.Sleep(100);
        readyState = (bool)jse.ExecuteScript("return ((document.readyState === 'complete') && (ae.isProcessing === false))");
        if (readyState) { i++; }
        else
        {
            i = 0;
            k++;
        }
        j++;
        if (j > 300) { throw new TimeoutException("Timeout waiting for document.readyState to be complete."); }
    }
    j *= 100;
    Console.WriteLine("Waited " + j.ToString() + " milliseconds. There were " + k + " resets.");
}

To do it properly, you need to handle the exceptions.要正确执行此操作,您需要处理异常。

Here is how I do a wait for an iFrame.这是我等待 iFrame 的方法。 This requires that your JUnit test class pass the instance of RemoteWebDriver into the page object :这要求您的 JUnit 测试类将 RemoteWebDriver 的实例传递到页面对象中:

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

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

NOTE: You can see my entire working example here .注意:您可以在此处查看我的整个工作示例

For the nodejs Selenium library, I used the following snippet.对于nodejs Selenium 库,我使用了以下代码段。 In my case, I was looking for two objects that are added to the window, which in this example are <SOME PROPERTY> , 10000 is the timeout milliseconds, <NEXT STEP HERE> is what happens after the properties are found on the window.就我而言,我正在寻找添加到窗口的两个对象,在本例中为<SOME PROPERTY>10000是超时毫秒, <NEXT STEP HERE>是在窗口上找到属性后发生的情况。

driver.wait( driver => {
    return driver.executeScript( 'if(window.hasOwnProperty(<SOME PROPERTY>) && window.hasOwnProperty(<SOME PROPERTY>)) return true;' ); }, 10000).then( ()=>{
        <NEXT STEP HERE>
}).catch(err => { 
    console.log("looking for window properties", err);
});

This works for me well with dynamically rendered websites:对于动态呈现的网站,这对我很有效:

  1. Wait for complete page to load等待完整页面加载

 WebDriverWait wait = new WebDriverWait(driver, 50); wait.until((ExpectedCondition<Boolean>) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));

  1. Make another implicit wait with a dummy condition which would always fail使用总是失败的虚拟条件进行另一个隐式等待

 try { wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(),'" + "This text will always fail :)" + "')]"))); // condition you are certain won't be true } catch (TimeoutException te) { }

  1. Finally, instead of getting the html source - which would in most of one page applications would give you a different result , pull the outerhtml of the first html tag最后,不是获取 html 源代码——这在大多数页面应用程序中会给你不同的结果,而是拉取第一个 html 标签的外层 html

 String script = "return document.getElementsByTagName(\\"html\\")[0].outerHTML;"; content = ((JavascriptExecutor) driver).executeScript(script).toString();

You can write some logic to handle this.您可以编写一些逻辑来处理此问题。 I have write a method that will return the WebElement and this method will be called three times or you can increase the time and add a null check for WebElement Here is an example我编写了一个返回WebElement的方法,该方法将被调用 3 次,或者您可以增加时间并为WebElement添加空检查这是一个示例

public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("https://www.crowdanalytix.com/#home");
        WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk");
        int i = 1;
        while (webElement == null && i < 4) {
            webElement = getWebElement(driver, "homessssssssssss");
            System.out.println("calling");
            i++;
        }
        System.out.println(webElement.getTagName());
        System.out.println("End");
        driver.close();
    }

    public static WebElement getWebElement(WebDriver driver, String id) {
        WebElement myDynamicElement = null;
        try {
            myDynamicElement = (new WebDriverWait(driver, 10))
                    .until(ExpectedConditions.presenceOfElementLocated(By
                            .id(id)));
            return myDynamicElement;
        } catch (TimeoutException ex) {
            return null;
        }
    }

Here's from my own code:这是我自己的代码:
Window.setTimeout executes only when browser is idle. Window.setTimeout 仅在浏览器空闲时执行。
So calling the function recursively (42 times) will take 100ms if there is no activity in the browser and much more if the browser is busy doing something else.因此,如果浏览器中没有活动,递归调用该函数(42 次)将需要 100 毫秒,如果浏览器忙于做其他事情,则需要更多时间。

    ExpectedCondition<Boolean> javascriptDone = new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver d) {
            try{//window.setTimeout executes only when browser is idle,
                //introduces needed wait time when javascript is running in browser
                return  ((Boolean) ((JavascriptExecutor) d).executeAsyncScript( 

                        " var callback =arguments[arguments.length - 1]; " +
                        " var count=42; " +
                        " setTimeout( collect, 0);" +
                        " function collect() { " +
                            " if(count-->0) { "+
                                " setTimeout( collect, 0); " +
                            " } "+
                            " else {callback(" +
                            "    true" +                            
                            " );}"+                             
                        " } "
                    ));
            }catch (Exception e) {
                return Boolean.FALSE;
            }
        }
    };
    WebDriverWait w = new WebDriverWait(driver,timeOut);  
    w.until(javascriptDone);
    w=null;

As a bonus the counter can be reset on document.readyState or on jQuery Ajax calls or if any jQuery animations are running (only if your app uses jQuery for ajax calls...)作为奖励,计数器可以在 document.readyState 或 jQuery Ajax 调用或任何 jQuery 动画正在运行时重置(仅当您的应用程序使用 jQuery 进行 ajax 调用时...)
... ...

" function collect() { " +
                            " if(!((typeof jQuery === 'undefined') || ((jQuery.active === 0) && ($(\":animated\").length === 0))) && (document.readyState === 'complete')){" +
                            "    count=42;" +
                            "    setTimeout( collect, 0); " +
                            " }" +
                            " else if(count-->0) { "+
                                " setTimeout( collect, 0); " +
                            " } "+ 

... ...

EDIT: I notice executeAsyncScript doesn't work well if a new page loads and the test might stop responding indefinetly, better to use this on instead.编辑:我注意到如果新页面加载并且测试可能会不确定地停止响应,我注意到 executeAsyncScript 不能正常工作,最好改用它。

public static ExpectedCondition<Boolean> documentNotActive(final int counter){ 
    return new ExpectedCondition<Boolean>() {
        boolean resetCount=true;
        @Override
        public Boolean apply(WebDriver d) {

            if(resetCount){
                ((JavascriptExecutor) d).executeScript(
                        "   window.mssCount="+counter+";\r\n" + 
                        "   window.mssJSDelay=function mssJSDelay(){\r\n" + 
                        "       if((typeof jQuery != 'undefined') && (jQuery.active !== 0 || $(\":animated\").length !== 0))\r\n" + 
                        "           window.mssCount="+counter+";\r\n" + 
                        "       window.mssCount-->0 &&\r\n" + 
                        "       setTimeout(window.mssJSDelay,window.mssCount+1);\r\n" + 
                        "   }\r\n" + 
                        "   window.mssJSDelay();");
                resetCount=false;
            }

            boolean ready=false;
            try{
                ready=-1==((Long) ((JavascriptExecutor) d).executeScript(
                        "if(typeof window.mssJSDelay!=\"function\"){\r\n" + 
                        "   window.mssCount="+counter+";\r\n" + 
                        "   window.mssJSDelay=function mssJSDelay(){\r\n" + 
                        "       if((typeof jQuery != 'undefined') && (jQuery.active !== 0 || $(\":animated\").length !== 0))\r\n" + 
                        "           window.mssCount="+counter+";\r\n" + 
                        "       window.mssCount-->0 &&\r\n" + 
                        "       setTimeout(window.mssJSDelay,window.mssCount+1);\r\n" + 
                        "   }\r\n" + 
                        "   window.mssJSDelay();\r\n" + 
                        "}\r\n" + 
                        "return window.mssCount;"));
            }
            catch (NoSuchWindowException a){
                a.printStackTrace();
                return true;
            }
            catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            return ready;
        }
        @Override
        public String toString() {
            return String.format("Timeout waiting for documentNotActive script");
        }
    };
}

I like your idea of polling the HTML until it's stable.我喜欢你轮询 HTML 直到它稳定的想法。 I may add that to my own solution.我可以将其添加到我自己的解决方案中。 The following approach is in C# and requires jQuery.以下方法是在 C# 中,需要 jQuery。

I'm the developer for a SuccessFactors (SaaS) test project where we have no influence at all over the developers or the characteristics of the DOM behind the web page.我是 SuccessFactors (SaaS) 测试项目的开发人员,我们对开发人员或网页背后的 DOM 特性没有任何影响。 The SaaS product can potentially change its underlying DOM design 4 times a year, so the hunt is permanently on for robust, performant ways to test with Selenium (including NOT testing with Selenium where possi ble!) SaaS 产品每年可能会更改其底层 DOM 设计 4 次,因此一直在寻找使用 Selenium 进行测试的稳健、高效的方法(包括在可能的情况下不使用 Selenium 进行测试!)

Here's what I use for "page ready".这是我用于“页面就绪”的内容。 It works in all my own tests currently.它目前适用于我自己的所有测试。 The same approach also worked for a big in-house Java web app a couple of years ago, and had been robust for over a year at the time I left the project.几年前,同样的方法也适用于一个大型的内部 Java Web 应用程序,并且在我离开该项目时已经运行了一年多。

  • Driver is the WebDriver instance that communicates with the browser Driver是与浏览器通信的 WebDriver 实例
  • DefaultPageLoadTimeout is a timeout value in ticks (100ns per tick) DefaultPageLoadTimeout是以滴答为单位的超时值(每滴答 100ns)

public IWebDriver Driver { get; private set; }

// ...

const int GlobalPageLoadTimeOutSecs = 10;
static readonly TimeSpan DefaultPageLoadTimeout =
    new TimeSpan((long) (10_000_000 * GlobalPageLoadTimeOutSecs));
Driver = new FirefoxDriver();

In what follows, note the order of waits in method PageReady (Selenium document ready, Ajax, animations), which makes sense if you think about it:在接下来的内容中,请注意方法PageReady的等待顺序(Selenium 文档就绪、Ajax、动画),如果您考虑一下,这很有意义:

  1. load the page containing the code加载包含代码的页面
  2. use the code to load the data from somewhere via Ajax使用代码通过 Ajax 从某处加载数据
  3. present the data, possibly with animations呈现数据,可能带有动画

Something like your DOM comparison approach could be used between 1 and 2 to add another layer of robustness.可以在 1 和 2 之间使用像您的 DOM 比较方法之类的东西来增加另一层稳健性。


public void PageReady()
{
    DocumentReady();
    AjaxReady();
    AnimationsReady();
}


private void DocumentReady()
{
    WaitForJavascript(script: "return document.readyState", result: "complete");
}

private void WaitForJavascript(string script, string result)
{
    new WebDriverWait(Driver, DefaultPageLoadTimeout).Until(
        d => ((IJavaScriptExecutor) d).ExecuteScript(script).Equals(result));
}

private void AjaxReady()
{
    WaitForJavascript(script: "return jQuery.active.toString()", result: "0");
}

private void AnimationsReady()
{
    WaitForJavascript(script: "return $(\"animated\").length.toString()", result: "0");
}

有没有人发现如何在React Application中获得活动的Ajax调用计数

Don't know how to do that but in my case, end of page load & rendering match with FAVICON displayed in Firefox tab.不知道该怎么做,但就我而言,页面加载结束和渲染与 Firefox 选项卡中显示的 FAVICON 匹配。

So if we can get the favicon image in the webbrowser, the web page is fully loaded.所以如果我们能在浏览器中获取到 favicon 图像,那么网页就完全加载了。

But how perform this ....但是如何执行这个......

Using implicit wait works for me.使用隐式等待对我有用。

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

Refer to this answer Selenium c# Webdriver: Wait Until Element is Present请参阅此答案Selenium c# Webdriver: Wait until Element is Present

In case of a complex/heavy webpage, it is always advisable to check for javascript and jQuery completion before performing any selenium test operations.对于复杂/繁重的网页,始终建议在执行任何 selenium 测试操作之前检查javascriptjQuery 是否完成。

When you test for jQuery completion do not forget to add a check for jQuery being undefined else you will end up with ReferenceError: jQuery is not defined error .当您测试 jQuery 完成时,不要忘记添加对 jQuery 未定义的检查,否则您将以ReferenceError: jQuery is not defined错误结束。

So you need to add below 2 checks:所以你需要添加以下 2 个检查:

  1. Javascript check : Javascript 查询

 return ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete")

  1. jQuery check : jQuery 查询

 (Boolean)((JavascriptExecutor) wd).executeScript("return window.jQuery.= undefined && jQuery.active == 0")

Now when you write method then I would suggest to use Fluent Wait in your selenium code rather than implicit or explicit wait.现在,当您编写方法时,我建议您在selenium 代码中使用Fluent Wait ,而不是隐式或显式等待。 Fluent wait method will help you do operation in between the polling interval wait unlike other waits and is very useful or rather powerful. Fluent wait 方法将帮助您在轮询间隔等待之间进行操作,这与其他等待不同,非常有用或相当强大。

Below is the working method which you can directly use:以下是您可以直接使用的工作方法:

 public static void pageJavaScriptAndJqueryLoad(WebDriver driver, Duration waitTimeout) { Wait<WebDriver> wait = new FluentWait<>(driver).withTimeout(waitTimeout).pollingEvery(Duration.ofMillis(500)).ignoring(NoSuchElementException.class); wait.until((ExpectedCondition<Boolean>) wd -> { log.info("Waiting for Page Javascript to load completely"); log.info("document.readyState value is: " + ((JavascriptExecutor) wd).executeScript("return document.readyState")); log.info("jQuery.active value is: " + ((JavascriptExecutor) wd).executeScript("return window.jQuery.= undefined && jQuery;active")). return ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete") && (Boolean)((JavascriptExecutor) wd).executeScript("return window.jQuery;= undefined && jQuery;active == 0"); }); }

In the above method:在上面的方法中:

  1. You need to pass your driver and waitTimeout duration as argument to this method.您需要将驱动程序和 waitTimeout 持续时间作为参数传递给此方法。 For ex: pageJavaScriptAndJqueryLoad(driver, Duration.ofSeconds(120)) ;例如: pageJavaScriptAndJqueryLoad(driver, Duration.ofSeconds(120)) ;
  2. I have defined polling interval as 500 ms.我已将轮询间隔定义为 500 毫秒。 You can modify as per your need.您可以根据需要进行修改。
  3. Every time a poll is done it prints the 3 statement given under log.info.每次完成轮询时,它都会打印 log.info 下给出的第 3 条语句。
  4. Using this you can easily add code to determine the exact time your page was rendered completely before doing test operations.使用它,您可以轻松添加代码以确定在执行测试操作之前完全呈现页面的确切时间。

Here is a python version for those that need it这里有一个python版本给有需要的人

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def wait_for_js_to_load(driver):
    wait = WebDriverWait(driver, 30)

    # Wait for jQuery to load
    jQuery_load = EC.presence_of_element_located((By.XPATH, "//script[contains(@src,'jquery')]"))
    wait.until(jQuery_load)

    # Wait for Javascript to load
    js_load = EC.presence_of_element_located((By.XPATH, "//script[contains(@src,'javascript')]"))
    wait.until(js_load)

Here's how I do it:这是我的方法:

new WebDriverWait(driver, 20).until(
       ExpectedConditions.jsReturnsValue(
                   "return document.readyState === 'complete' ? true : false"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM