【问题标题】:Detecting that Angular 2 is done running检测到 Angular 2 已完成运行
【发布时间】:2016-11-01 20:02:13
【问题描述】:

我们使用 Selenium WebDriver 来自动化我们基于 UI 的测试。我们面临的挑战之一是检测页面何时真正完成加载,Angular 1 在这方面也是一个挑战。我们最终专门执行了这段代码来检测 Angular 1 是否完成:

if(typeof window.angular !== \"undefined\")
{
  var injector = window.angular.element(\"*[ng-app]\").eq(0).injector();

  if(injector)
  {
    var $rootScope = injector.get(\"$rootScope\");
    var $http = injector.get(\"$http\");

    if($rootScope.$$phase === \"$apply\" || $rootScope.$$phase === \"$digest\" || $http.pendingRequests.length !== 0)
    {
      return false;
    }
  }
}

我们最近测试的应用程序切换到使用 Angular 2。上面的代码 sn-p 不等待 Angular 2 完成。有什么建议吗?

【问题讨论】:

标签: selenium angular webdriver


【解决方案1】:

如果是 Angular 2,您应该等待所有 Angular 2 应用程序的"testabilities" 稳定

functions.waitForAllAngular2 = function(callback) {
  try {
    var testabilities = window.getAllAngularTestabilities();
    var count = testabilities.length;
    var decrement = function() {
      count--;
      if (count === 0) {
        callback();
      }
    };
    testabilities.forEach(function(testability) {
      testability.whenStable(decrement);
    });
  } catch (err) {
    callback(err.message);
  }
};

Taken from Protractor source code。 Protractor 是 WebDriverJS javascript selenium 绑定的包装器;旨在测试 AngularJS 应用程序(不仅,而且最适合)。

【讨论】:

    【解决方案2】:

    使用@alecxe 答案,我最终使用了 javascript 一行来检查所有 Angular Testabilities 是否稳定

    window.getAllAngularTestabilities().findIndex(x=>!x.isStable()) === -1
    

    【讨论】:

      【解决方案3】:

      基于 alexce 的回答,这是我们在 selenium 测试中用于等待 angular 的代码:

      public static void waitForPageLoaded(WebDriver webDriver) {
          ExpectedCondition<Boolean> expectation = new
                  ExpectedCondition<Boolean>() {
                      public Boolean apply(WebDriver driver) {
                          return ((JavascriptExecutor) driver).executeAsyncScript(
                              "var callback = arguments[arguments.length - 1];" +
                              "if (document.readyState !== 'complete') {" +
                              "  callback('document not ready');" +
                              "} else {" +
                              "  try {" +
                              "    var testabilities = window.getAllAngularTestabilities();" +
                              "    var count = testabilities.length;" +
                              "    var decrement = function() {" +
                              "      count--;" +
                              "      if (count === 0) {" +
                              "        callback('complete');" +
                              "      }" +
                              "    };" +
                              "    testabilities.forEach(function(testability) {" +
                              "      testability.whenStable(decrement);" +
                              "    });" +
                              "  } catch (err) {" +
                              "    callback(err.message);" +
                              "  }" +
                              "}"
                          ).toString().equals("complete");
                      }
                  };
          try {
              WebDriverWait wait = new WebDriverWait(webDriver, waitSeconds);
              wait.until(expectation);
          } catch (Throwable error) {
              new Exception("Timeout waiting for Page Load Request to complete.");
          }
      } 
      

      【讨论】:

        【解决方案4】:

        我通过编写一个动作类来解决这个问题,我在使用 Paul Hammants ngWebDriver 执行动作(单击、填充、检查等)之前等待 Angular:

        import com.paulhammant.ngwebdriver.NgWebDriver;
        
        public class ActionsWithWaits {
        
        private NgWebDriver ngdriver;
        private JavascriptExecutor js;
        
        public ActionsWithWaits(){
            WebDriver driver = getDriver();
            js = (JavascriptExecutor) driver;
            driver.manage().timeouts().setScriptTimeout(9, TimeUnit.SECONDS);
            ngdriver = new NgWebDriver(js);
        }
        
        
        public void waitForAngular(){
            ngdriver.waitForAngularRequestsToFinish();
        }
        
        public void waitAndClick(WebElementFacade button){
            waitForAngular();
            button.click();
        }
        
        public void waitAndFillIn(String text, WebElementFacade field){
            waitForAngular();
            field.type(text);
        }
        
        etc..
        

        现在您可以只使用这些操作而不是标准的 selenium 操作,而且您不必担心任何事情(=

        【讨论】:

          【解决方案5】:

          我会在根组件的ngAfterViewInit() 内发出一个事件

          @Component({
            selector: 'my-app',
            ...
          })
          export class AppComponent {
            constructor(private renderer:Renderer, private elementRef:ElementRef){}
            ngAfterViewInit() {
              this.renderer.invokeElementMethod(this.elementRef.nativeElement, 
                  'dispatchEvent', 
                  [new CustomEvent('angular2-loaded', { bubbles: true })]);
            }
          }
          

          然后使用 WebDriver 监听这个事件。

          【讨论】:

          • 上面有一个错字:在构造函数参数中,第二个参数是 elementRef 但在 ngAfterViewInit() 中您使用的是 elRef。无论如何,我们尝试将其添加到正在测试的主要 NG2 组件的应用程序中。然后在 Chrome 控制台中,我们注册以侦听 angular2-loaded 事件,并传入一个简单的回调来提醒。加载了正在测试的应用程序,然后……什么也没发生。
          • @user1801355 感谢您的提示。我不知何故错过了您的评论 - 已修复。
          猜你喜欢
          • 2010-09-29
          • 1970-01-01
          • 2012-01-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-13
          相关资源
          最近更新 更多