【问题标题】:Selenium - Wait for network trafficSelenium - 等待网络流量
【发布时间】:2011-05-05 20:46:47
【问题描述】:

我们将 Selenium 与 Java API 和一些 Javascript 用户扩展一起使用。我们在我们的应用程序中使用了很多 AJAX 调用。我们的很多测试都是随机失败的,因为有时 AJAX 调用的完成速度比其他时间慢,因此页面没有完全加载。我们通过等待特定元素或 Thread.sleep 来解决这个问题。我试图找到一种方法来等待网络流量完成。所以我们可以这样做:

selenium.click("some JS button");
selenium.waitForNetwork();
assertTrue(something);

这样我们就可以摆脱线程休眠并在服务器响应更快时更快地通过测试,并且不会因为时间问题而导致太多测试失败。

我无法通过 Google 搜索找到一种方法。有谁知道我们如何做到这一点? (最好通过 Javascript 或 Java API,但欢迎所有建议)。

注意:“waitFor”的其他变体不是我想要的。我们已经在点击和其他事情中使用了这些。我正在寻找等待网络流量的东西。感谢所有反馈,我会尝试一些建议,但我仍然愿意接受其他想法。

谢谢。

【问题讨论】:

    标签: java networking selenium


    【解决方案1】:

    是的,做这样的事情(伪代码):

    int i = 0;
    while (element is not yet present) {
      i++;
      if (i>TRESHOLD) {
        throw an exception
      }
      Thread.sleep(200);
    }
    //go on
    

    你可能想把它塞进一个函数中。

    【讨论】:

      【解决方案2】:

      Selenium 中提供的 waitFor 类型很少。在您的测试用例中,如果您知道页面加载时会出现特定文本,您可以使用 waitForText。如果填充了不同的 DOM 元素(通过 Ajax/pageload),您可以按顺序添加 waitForText。

      【讨论】:

        【解决方案3】:

        我们已经有了在 AJAX 请求期间更改鼠标光标的客户端代码(使用 a4j:status 和属性 onstart 和 onstop)。因此我们可以简单地等待JavaScript表达式的值

        window.document.body.style.cursor
        

        但是,我发现这并不可靠,即有时测试进行得太早。我不确定原因,但怀疑在调用 onstop 时更新 DOM 不一定完全完成。

        至于减少不必要的延迟,您可以自己实现轮询,并且比 selenium 更频繁地进行轮询。

        【讨论】:

          【解决方案4】:

          在尝试了此页面上描述的所有变体之后,我们最终采用了以下策略:

          注入一个特殊的 javascript,它基本上会覆盖所有相关的框架方法,并保留一个未完成请求数量的 计数器,该数量在启动时递增,在完成时递减。由于 javascript 的异步特性,不够保留布尔变量,您可能会在自己的逻辑中遇到竞争条件。

          如果您正在使用视觉效果,您可能也希望为视觉效果这样做;变形/褪色和其他视觉效果也会有同样的问题。

          所以我们基本上做一个常规的“点击”,然后总是等待这个计数器再次达到 0,就像其他人在这里建议的那样使用 javascript。完成此操作后,我们将暂时性问题减少到无。

          请记住,在处理完所有同步 onclick 事件之前,selenium 不会从“click”返回,因此您必须确保这些计数器作为 onclick 的直接结果而递增。

          有关如何覆盖框架方法的说明,您需要查阅框架文档;我们在原型中使用 addMethods。可以将此覆盖保留在仅在运行测试时添加到页面的特殊 javascript 中。

          【讨论】:

          • 我们为我们内部构建的 AJAX 框架做同样的事情,在 WaitForCondition() 中调用 IsTheCountZeroYet() 函数。我知道你可以很容易地用 jQuery 做到这一点。可能还有其他框架。
          • 有趣的是prototype.js中的ajax计数器有问题,它们并不总是返回0。而且视觉效果还没有这种计数器。所以我们不得不自己动手。
          【解决方案5】:

          这可能不适合您,但由于类似的问题,我们移至 Selenium 2(又名 WebDriver)。我们使用PageFactory 和AjaxElementLocatorFactory

          为了使迁移更容易,有一个Selenium Emulation,计划是完全合并 Selenium 1 和 WebDriver,这是 Selenium 2 的主要目标。

          【讨论】:

            【解决方案6】:

            更新:我以与 Selenium2 相同的方式使用相同的方法 (wrapRequest),它仍然有效。唯一的区别是我不使用用户扩展。我只是执行javascript来查询JSP加载的代码。

            这就是我们最终要做的事情。 (请注意,如果您始终只使用像 JQuery 这样的单一框架,则有更简单的方法来获取 Ajax 调用是否正在运行。我们不得不对它进行更多的调整,因为我们有一些使用 JQuery 的页面和一堆使用 GWT)

            我创建了一个 Javascript 文件,只有在您进行测试时才会加载每个页面。 (我通过在我们的 JSP 模板中包含一个 sn-p 来做到这一点:如果测试查询字符串参数作为 true 传入,则设置一个 cookie。如果设置了该 cookie,则包含 javascript 文件) 这个 javascript 文件本质上包装了 XMLHttpRequest 对象以记录所有发送请求:

            function wrapRequest(xmlRequest) {
                var oldSend = xmlRequest.prototype.send;
                xmlRequest.prototype.send = function() {
                    var oldOnReady = this.onreadystatechange;
                    oldOnReady = function() {
                        oldOnReady.apply(this, arguments);
                        // if call is complete, decrement counter.
                    }
                    // increment counter
                    if(oldSend.apply)
                        oldSend.apply(this, arguments);
                    else if (oldOnReady.handleEvent) { //Firefox sometimes will need this
                        oldOnReady.handleEvent.apply(this, arguments);
                    }
                }
            }
            

            如果 async == false 的话,还有一些问题,但这应该很容易弄清楚。

            然后我在 selenium user-extensions.js 中添加了一个函数,看起来像这样:

            Selenium.prototype.getIsNetworkReady = function() {
                if(this.browserbot.topWindow.isNetworkReady) { //sometimes this method is called before the page has loaded the isNetworkReady function
                    return this.browserbot.topWindow.isNetworkReady();
                }
                return false;
            }
            

            另外,请注意 topWindow 上的检查:这是因为您在选择 iframe 时遇到问题。

            此外,您必须在每个加载的 iFrame 的 XMLHttpRequest 对象上调用 wrapRequest 方法。我现在使用:document.addEventListener("DOMNodeInserted", onElementAdded, true); 执行此操作,然后在 onElementAdded 中,我只是在加载 iframe 时抓取它并传入 XMLHttpRequest 对象。但这在 IE 中不起作用,所以我正在寻找替代方案。如果有人知道更好的方法来做到这一点,那么它可以在 IE 和 FF 中工作,我很想听听。

            无论如何,这就是实施的要点。希望这对将来的任何人都有帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-07-07
              • 1970-01-01
              • 1970-01-01
              • 2019-11-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多