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

psa*_*dac 95 c# java selenium webdriver selenium-webdriver

我有一个用Selenium测试的Web应用程序.页面加载时会运行很多JavaScript.
这段JavaScript代码编写得不是很好,但我无法改变任何东西.所以等待元素出现在DOM中的findElement()方法不是一种选择.
我想在Java中创建一个通用函数来等待页面加载,可能的解决方案是:

  • 从WebDriver运行JavaScript脚本并将结果存储document.body.innerHTML在字符串变量中body.
  • body变量与之前版本进行比较body.如果它们相同则设置增量计数器,notChangedCount否则设置notChangedCount为零.
  • 等待一个小时(例如50毫秒).
  • 如果页面没有改变一段时间(例如500毫秒),notChangedCount >= 10那么退出循环,否则循环到第一步.

你认为这是一个有效的解决方案吗?

Pet*_*ček 65

如果有人真的知道一般的,总是适用的答案,它会很久以前的任何地方实施,并且会让我们的生活变得更加容易.

你可以做很多事情,但每一个都有问题:

  1. 正如阿什温帕布说,如果你知道剧本好,你可以观察它的行为,并跟踪它的一些变量对windowdocument等此解决方案,但是,是不是对每个人都可以通过你,只有在有限的一组只用页面.

  2. 通过观察HTML代码以及它是否已经有一段时间没有被更改的解决方案并不坏(同样,有一种方法可以直接获取原始的和未经编辑的HTML WebDriver),但是:

    • 实际断言页面需要很长时间才能显着延长测试时间.
    • 你永远不知道什么是正确的间隔.该脚本可能正在下载超过500毫秒的大型内容.我们公司的内部页面上有几个脚本在IE中需要几秒钟.您的计算机可能暂时缺少资源 - 比如防病毒软件会让您的CPU完全运行,那么即使对于非复杂的脚本,500毫秒也可能太短.
    • 有些脚本永远不会完成.他们称自己有一些延迟(setTimeout())并且一次又一次地工作,并且每次运行时都可能改变HTML.说真的,每个"Web 2.0"页面都能做到.甚至Stack Overflow.您可以覆盖最常用的方法并考虑使用它们完成的脚本,但是......您无法确定.
    • 如果脚本执行除更改HTML之外的其他操作,该怎么办?它可以做成千上万的事情,而不仅仅是一些innerHTML乐趣.
  3. 有一些工具可以帮助您.即Progress ListenersnsIWebProgressListener以及其他一些.然而,浏览器对此的支持非常糟糕.Firefox开始尝试从FF4开始支持它(仍在不断发展),IE在IE9中有基本支持.

我想我很快就会想出另一个有缺陷的解决方案.事实是 - 由于永久的脚本正在完成他们的工作,所以没有明确的答案何时说"现在页面已完成".选择最适合你的那个,但要注意它的缺点.


Edu*_*cio 29

谢谢Ashwin!

在我的情况下,我应该等待在某个元素中执行jquery插件..特别是"qtip"

根据你的提示,它对我来说非常有用:

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

注意:我正在使用Webdriver 2

  • 此代码块对我来说很棒。 (2认同)
  • 这对我也很好。就我而言,页面加载完成后,Javascript修改了一个元素,而Selenium并没有隐式等待它。 (2认同)
  • 谓词从哪里来?哪个进口? (2认同)

LIN*_*NGS 26

你需要等待Javascript和jQuery才能完成加载.执行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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不确定这是否适用于_every_环境,但它对我的用例有用 (2认同)

Ash*_*bhu 10

JS库是否定义/初始化窗口上任何众所周知的变量?

如果是这样,您可以等待变量出现.您可以使用

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

测试这个条件(类似于window.SomeClass && window.SomeClass.variable != null:)并返回一个布尔值true/ false.

将其包装在a中WebDriverWait,并等待脚本返回true.


Rom*_*Kap 8

我有同样的问题。这个解决方案适用于 WebDriverDoku:

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

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


The*_*ilo 6

如果您需要做的就是等待页面上的html稳定之后再尝试与元素进行交互,则可以定期轮询DOM并比较结果,如果在给定的轮询时间内DOM相同,则说明金。像这样的事情,您需要传递最大等待时间以及进行比较之前的两次页面轮询之间的时间。简单有效。

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我想在这里指出,我记录了两次轮询中等大小页面所花费的时间,然后在 Java 中比较这些字符串,花费了 20 多毫秒。 (2认同)
  • 起初,我发现这是一个肮脏的解决方案,但它似乎工作得很好,并且不涉及在客户端设置变量。一个警告可能是一个页面,该页面经常被javascript(即javascript时钟)更改,但是我没有,所以它可以工作! (2认同)