UI路由器与$ httpbackendunit testing,angular度js干涉

这是一个提交function的控制器:

$scope.submit = function(){ $http.post('/api/project', $scope.project) .success(function(data, status){ $modalInstance.dismiss(true); }) .error(function(data){ console.log(data); }) } } 

这是我的testing

 it('should make a post to /api/project on submit and close the modal on success', function() { scope.submit(); $httpBackend.expectPOST('/api/project').respond(200, 'test'); $httpBackend.flush(); expect(modalInstance.dismiss).toHaveBeenCalledWith(true); }); 

我得到的错误是:

 Error: Unexpected request: GET views/appBar.html 

views / appBar.html是我的templateUrl:

  .state('project', { url: '/', templateUrl:'views/appBar.html', controller: 'ProjectsCtrl' }) 

所以不知何故ui路由器使我的$ httpBackend指向这个,而不是我的提交function。 我在使用$ httpBackend的所有testing中遇到同样的问题。

有没有解决这个问题?

采取这个要点https://gist.github.com/wilsonwc/8358542

 angular.module('stateMock',[]); angular.module('stateMock').service("$state", function($q){ this.expectedTransitions = []; this.transitionTo = function(stateName){ if(this.expectedTransitions.length > 0){ var expectedState = this.expectedTransitions.shift(); if(expectedState !== stateName){ throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName ); } }else{ throw Error("No more transitions were expected! Tried to transition to "+ stateName ); } console.log("Mock transition to: " + stateName); var deferred = $q.defer(); var promise = deferred.promise; deferred.resolve(); return promise; } this.go = this.transitionTo; this.expectTransitionTo = function(stateName){ this.expectedTransitions.push(stateName); } this.ensureAllTransitionsHappened = function(){ if(this.expectedTransitions.length > 0){ throw Error("Not all transitions happened!"); } } }); 

把它添加到你的test / mock文件夹中的一个名为stateMock的文件中,如果它还没有被拾取,那么把它包含在你的karmaconfiguration中。

testing之前的设置应该如下所示:

 beforeEach(module('stateMock')); // Initialize the controller and a mock scope beforeEach(inject(function ($state //other vars as needed) { state = $state; //initialize other stuff } 

然后在你的testing中,你应该添加

 state.expectTransitionTo('project'); 

关于unit testingUI路由器的这个Github问题更全面地解释了发生了什么。

问题是$httpBackend.flush()触发广播,然后触发stateProvider

一个简单的解决scheme可以做到以下设置,就像上面提到的Github线程中的@darinclark所提到的那样。 如果你不需要testing状态转换,这是有效的。 否则看看@ rosswil的答案是由Github上的@Vratislav答案所启发的。

 beforeEach(module(function ($urlRouterProvider) { $urlRouterProvider.otherwise(function(){return false;}); })); 

EDITED

感谢Chris T在评论中报告这个,似乎在v0.2.14之后? 最好的办法是使用

 beforeEach(module(function($urlRouterProvider) { $urlRouterProvider.deferIntercept(); })); 

如果你不想像在正确的解决scheme中说的那样添加gist文件,你可以在你的$ httpBackend中添加一个“when”条件来忽略这样的GET请求:

 $httpBackend.when("GET", function (url) { // This condition works for my needs, but maybe you need to improve it return url.indexOf(".tpl.html") !== -1; }).passThrough(); 

我有同样的错误你的评论,在通话服务后,他们问我有关其他ui-route的url。

为了解决调用其他ui-routetesting的问题,在之前的注释中 没有注入$ state 。 在我的testing$状态没有意义使用它。

把你的服务移到他们自己的模块上,这个模块不依赖于ui.router。 有你的主要应用程序依赖于这个模块。 当你testing的时候不要testing主应用程序,testing一下你的服务的模块。 状态提供者不会尝试改变状态/路由,因为这个模块对ui.router一无所知。 这对我有效。

Interesting Posts