用于调试Protractor-Angular同步问题的规范方法

时间:2017-03-17 19:06:22

标签: javascript angularjs selenium protractor

问题描述:

我们最近在Protractor端到端测试中打开我们应用程序中的一个页面时遇到了这个臭名昭着的错误:

  

失败:等待异步Angular任务在50秒后完成超时。这可能是因为当前页面不是Angular应用程序。

在我们的某个测试中>>> import requests >>> w3schools = requests.get('http://www.w3schools.com/tags/default.asp').text >>> from lxml import html >>> tree = html.fromstring(w3schools) >>> links = tree.xpath('//table[@class="w3-table-all notranslate"]//a') >>> len(links) 119 >>> descrips = tree.xpath('//table[@class="w3-table-all notranslate"]//td[2]') >>> len(descrips) 119 >>> links[0].attrib {'href': 'tag_comment.asp'} >>> descrips[0].text 'Defines a comment' 调用时会发生这种情况:

browser.get("/some/page/");

而且,我们的案例有点奇怪,我们的Angular Web应用程序中的任何其他页面都没有抛出错误 - Protractor与Angular同步而没有任何问题。所有网页中describe("Test", function () { beforeEach(function () { browser.get("/some/page/"); }); it("should test something", function () { // ... }); )}; 位置相同的内容都是相同的 - ng-app在根ng-app标记上定义:

html

行为是一致的 - 每次我们使用<html class="ng-scope" lang="en-us" ng-app="myApp" ng-strict-di=""> 导航到此页面时,都会收到此错误。每当我们导航到我们应用中的任何其他页面时,同步都可以。

请注意,当然,我们可以关闭此页面的同步并将其视为非角度,但这只能被视为一种解决方法。

问题:

还有什么可能导致量角器到角度同步失败?我们应该检查什么?

一般来说,在Protractor中调试同步问题的推荐方法是什么?

使用当前最新的Protractor 5.5.1,Angular 1.5.6。

2 个答案:

答案 0 :(得分:7)

好的,这个问题引起了我的兴趣,所以我提出了一个关于如何确定量角器等待的程序化解决方案:

var _injector = angular.element(document).injector();
var _$browser = _injector.get('$browser');
var _$http = _injector.get('$http');
var pendingTimeout = true;

//this is actually method that protractor is using while waiting to sync
//if callback is called immediately that means there are no $timeout or $http calls
_$browser.notifyWhenNoOutstandingRequests(function callback () {
  pendingTimeout = false
});

setTimeout(function () {
  //this is to differentiate between $http and timeouts from the "notifyWhenNoOutstandingRequests" method
  if (_$http.pendingRequests.length) {
    console.log('Outstanding $http requests', _$http.pendingRequests.length)
  } else if (pendingTimeout) {
    console.log('Outstanding timeout')
  } else {
    console.log('All fine in Angular, it has to be something else')
  }
}, 100)

在plunker http://plnkr.co/edit/O0CkpnsnUuwEAV8I2Jil?p=preview中您可以尝试超时和$ http呼叫,我的延迟端点将在解决呼叫之前等待10秒,希望这对您有所帮助

答案 1 :(得分:1)

我同意@maurycy的问题是$ http / $ timeout相关。简单修复通常是用$ interval替换$ timeout,如下所示:https://github.com/angular/protractor/blob/master/docs/timeouts.md

建议: merge these sane defaults: allScriptsTimeout: 60000, // 1 minute jasmineNodeOpts: { defaultTimeoutInterval: 300000 // 5 minutes. Allows for 5 commands spanning the full synchronization timeout. }

如果你想找到$ http / $ timeout的罪魁祸首,我会使用角度修饰器来围绕这些服务应用自定义逻辑。这也是模拟角度服务访问第三方服务的好方法。 https://docs.angularjs.org/guide/decorators

//DISCLOSURE: Unlinted & Untested.
beforeAll(() => {
  browser.addMockModule('culpritMock', () => {
    angular.module('culpritMock', [])
      .config(['$httpProvider',
        $httpProvider => $httpProvider.interceptors.push('httpCounterInterceptor')
      ])
      .factory('httpCounterInterceptor', ['$q', '$window', ($q, $window) => {
        if ($window.httpCounterInterceptor == null) {
          $window.httpCounterInterceptor = {};
        }
        return {
          request: config => {
            $window.httpCounterInterceptor[config.url] = 'started';
            return config;
          },
          response: response => {
            $window.httpCounterInterceptor[response.config.url] = 'completed';
            return response;
          },
          responseError: rejection => {
            $window.httpCounterInterceptor[rejection.config.url] = 'error';
            return $q.reject(rejection);
          }
        };
      }])
      .decorator('$timeout', ['$delegate', $delegate => {
        const originalTimeout = $delegate;
        function modifiedTimeout() {
          console.log(arguments);
         return originalTimeout.apply(null, arguments);
        }
        modifiedTimeout.cancel = function(promise) {
          return $delegate.cancel(promise);
        }
        return modifiedTimeout;
      }]);
  });
});