从硒中检测角度是否正在做...的事情

2024-02-15

为什么driver.findElement(<some static element ng-if=simplebool>static text</some>).getText()曾经返回“”吗?

我有一个角度应用程序,我正在 osx 上通过 chromedriver 通过 java 使用 selenium 进行测试。

我有一些看起来像这样的标记:

<h1 id="my-unique-id" ng-if="model.shouldDisplayThisAttribute">static text</h1>

我经常得到:

assert(driver.findElement(By.id("my-unique-id").getText().contains("static text");

产量:

java.lang.AssertionError: Not true that <""> contains <"static text">

比如,30%的时间。

我不明白该元素的 .getText() 如何计算为“”,因此我假设 Angular 是 $digesting 或 $compiling 页面。没关系。没关系。没关系。

我想知道 Angular 何时完成 $compiling、$digesting 和 $watching,这样我就可以查看页面并查看内容。

如果我添加:

(function() 
   function angularAppearsToBeIdle(callback) {
     var untilNextDigest,
        isIdle = angular.element(document.body).scope().$watch(function () {
           clearTimeout(untilNextDigest);
           untilNextDigest = setTimeout(function () {
           isIdle();
           callback('done');
         }, 100);
      });
    }
 angularAppearsToBeIdle(console.log.bind(console));
}());

在我的页面上,我在预期的时间看到了 console.log 消息。

如果我将其粘贴到控制台中:

(function() {
   function angularAppearsToBeIdle(callback) {
       var untilNextDigest,
       isIdle = angular.element(document.body).scope().$watch(function () {
           clearTimeout(untilNextDigest);
           untilNextDigest = setTimeout(function () {
               isIdle();
               callback('done');
           }, 100);
       });
   }
   angularAppearsToBeIdle(console.log.bind(console));
}());

我得到“未定义”。

最终,我想做的是 Java:

@Test
public void clickOnSomethingThatIsProbablyNotGoingToChange(driver.findElement(By.id("some-id"));

private WebElement idleElement() {

    new WebDriverWait(driver, 30).until(new Predicate<WebDriver>() {
        @Override
        public boolean apply(WebDriver input) {
            Object result = ((JavascriptExecutor) driver).executeScript("return window.angularAppearsToBeIdle;");
            return result.equals("idle");
        }
   }

我已经尝试过以下操作,但没有 Selenium 执行类似操作的示例:

public void waitForAngular() {

    ((JavascriptExecutor) driver).executeScript(
            " window.angularAppearsToBeIdle = 'not idle'; ");

    ((JavascriptExecutor) driver).executeScript(
            " window.signalThatAngularAppearsToBeIdle = function(signal) { " +
            " var untilNextDigest, " +
            " isIdle = angular.element(document.body).scope().$watch(function () { " +
            "    clearTimeout(untilNextDigest); " +
            "    untilNextDigest = setTimeout(function () { " +
            "       isIdle(); " +
            "       signal = 'idle'; " +
            "    }, 100); " +
            "  }); " +
            " } ");

    driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);

    ((JavascriptExecutor) driver).executeAsyncScript(
            " var callback = arguments[arguments.length - 1]; " +
                    " signalThatAngularAppearsToBeIdle(callback) "
            ,
            " window.angularAppearsToBeIdle ");

    new WebDriverWait(driver, 30).until(new Predicate<WebDriver>() {
        @Override
        public boolean apply(WebDriver input) {
            Object result = ((JavascriptExecutor) driver).executeScript("return window.angularAppearsToBeIdle;");
            return result.equals("idle");

        }
    });

如果 Angular 正忙于做事情,我如何从 Selenium 中检测到?


您将需要编写一个自定义 ExpectedCondition 来查询 Angular 以查看它是否完成。这是我之前准备的:

    public static ExpectedCondition angularHasFinishedProcessing() {
        return new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driver) {
                String hasAngularFinishedScript = "var callback = arguments[arguments.length - 1];\n" +
                        "var el = document.querySelector('html');\n" +
                        "if (!window.angular) {\n" +
                        "    callback('false')\n" +
                        "}\n" +
                        "if (angular.getTestability) {\n" +
                        "    angular.getTestability(el).whenStable(function(){callback('true')});\n" +
                        "} else {\n" +
                        "    if (!angular.element(el).injector()) {\n" +
                        "        callback('false')\n" +
                        "    }\n" +
                        "    var browser = angular.element(el).injector().get('$browser');\n" +
                        "    browser.notifyWhenNoOutstandingRequests(function(){callback('true')});\n" +
                        "}";

                JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
                String isProcessingFinished = javascriptExecutor.executeAsyncScript(hasAngularFinishedScript).toString();

                return Boolean.valueOf(isProcessingFinished);
            }
        };
    }

这是假设您已经在 html 元素上定义了 ng-app 。如果您在 DOM 中的其他位置定义它,则需要更新上面的代码。这几乎是从 Protractor 窃取的,它正在检查是否有任何未完成的 ajax 请求,并检查 Angular 是否认为它处于可测试状态。

重要的部分是将这个 JavaScript 片段作为异步脚本执行,因为 Angular 使用 Promise 在准备好时触发回调。如果您不将其作为异步脚本运行,它将无法工作。

您还需要在驱动程序对象上设置脚本超时,这是 selenium 在抛出超时异常之前等待回调完成的时间。您可以按如下方式设置:

driver.manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS);

然后就像将此 ExpectedCondition 插入等待一样简单,如下所示:

WebDriverWait wait = new WebDriverWait(driver, 15, 100);
wait.until(angularHasFinishedProcessing());

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从硒中检测角度是否正在做...的事情 的相关文章

随机推荐