Javascript 带$httpbackend单元测试的UI路由器接口,angular js

Javascript 带$httpbackend单元测试的UI路由器接口,angular js,javascript,angularjs,angular-ui,karma-runner,angular-ui-router,Javascript,Angularjs,Angular Ui,Karma Runner,Angular Ui Router,这是一个具有提交功能的控制器: $scope.submit = function(){ $http.post('/api/project', $scope.project) .success(function(data, status){ $modalInstance.dismiss(true); }) .error(function(data){ console.log(data); }) } }

这是一个具有提交功能的控制器:

$scope.submit = function(){   

 $http.post('/api/project', $scope.project)
      .success(function(data, status){
        $modalInstance.dismiss(true);
      })
      .error(function(data){
        console.log(data);
      })
  }
}
这是我的测试

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是我的模板URL:

 .state('project', {
    url: '/',
    templateUrl:'views/appBar.html',
    controller: 'ProjectsCtrl'
  })
所以,不知怎的,ui路由器让我的$httpBackend指向这个,而不是我的提交函数。我在使用$httpBackend的所有测试中都遇到了相同的问题

有什么解决办法吗?

就拿这个要点吧

将其添加到test/mock文件夹中名为stateMock的文件中,如果尚未拾取该文件,请将其包含在karma配置中

测试前的设置应如下所示:

beforeEach(module('stateMock'));

// Initialize the controller and a mock scope
beforeEach(inject(function ($state //other vars as needed) {
    state = $state;
    //initialize other stuff
}
$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();
那么在你的测试中你应该添加

state.expectTransitionTo('project');
关于Github的这个问题更全面地解释了正在发生的事情

问题是
$httpBackend.flush()
触发了一个广播,然后触发了
状态提供程序的异常情况

一个简单的解决方案是执行以下设置,正如上面提到的Github线程中的@darinclark所提到的。如果不需要测试状态转换,则此选项有效。否则,看看这是什么启发

已编辑

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

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

将您的服务移动到它们自己的模块,这些模块不依赖于ui.router。让您的主应用程序依赖于此模块。测试时,不要测试主应用程序,测试其中包含您的服务的模块。stateprovider不会尝试更改状态/路由,因为此模块对ui.router一无所知。这对我有用

如果您不想在正确的解决方案中添加gist文件,您可以在$httpBackend中添加一个“when”条件,以忽略以下视图请求:

beforeEach(module('stateMock'));

// Initialize the controller and a mock scope
beforeEach(inject(function ($state //other vars as needed) {
    state = $state;
    //initialize other stuff
}
$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();

我有同样的错误,你的评论,在一个电话服务后,他们问我关于其他用户界面路由的url


要解决调用测试中的其他ui路由的问题,请在每个station之前的不注入$state。在我的测试中,$state没有使用它的意义

太棒了!我几乎都跳过了ui路由器。干得好!你应该和用户界面路由器的人分享这项工作,这样人们才能更好地找到它。@user1572526是的,太棒了+1 rosswil只是一个巨大的头痛^^我觉得奇怪的是这里没有很多人……哇,这需要与ui路由器共享,花了几个小时试图确定为什么注释我的$urlRouterProvider会修复我的测试。谢谢rosswil和Whisher指点我这里!!!使用ui路由器v0.2.11(1937:19)获取“TypeError:无法读取未定义的属性“$current”。registerState方法崩溃,$state未定义。是否有人有相同的问题?这是否可以用来测试是否使用
$state.go
在转换上传递了正确的
$stateParams
?ie:测试
$state.go('users',{name:'Bob'})
是否正确地传递了
{name:'Bob'}
作为转换的一部分?相关的UI路由器问题#212和一些解决方法:UI路由器现在有了
$urlRouterProvider.deferIntercept()
函数。看,这是最快的solution@ChrisT,您的解决方案是最优雅的。谢谢你的发帖!问题是$httpBackend.flush()触发广播,然后触发stateProvider的其他情况。这可能正是大多数人正在经历的事情。
$urlRouterProvider
从v1.0.0开始就被弃用了。使用
$urlServiceProvider.deferIntercept()。passThrough不是一个函数
错误,不知道为什么。这对我有用:
$httpBackend.whenGET(/templates\/.*/).respond(“”)您可以在这里看到文档,passThrough是一个有效函数:是来自requestHandler的函数,它是“when”函数的答案。即使我得到了。passThrough不是一个函数错误。“”。respond“虽然工作正常。
。在角度e2e测试(
ngMockE2E
)中可以使用passThrough,但在单元测试中不可用(
ngMock