ui-router的单元测试:在$ state.transitionTo()之后无法获得$ state.current来包含当前状态

时间:2013-10-05 11:21:00

标签: unit-testing angularjs angular-ui-router

我正在尝试为ui-router的状态编写单元测试,并且无法使其工作,以便在我在测试中调用$state.current之后$state.transitionTo()在控制器内包含正确的状态。

这适用于浏览器(其中transitionTo在内部由ui-router调用),但不在单元测试中(使用Karma) - 我明确地称之为。

这是控制器的代码:

angular.module( 'ngBoilerplate.about', [
  'ui.router'
])

.config(function config( $stateProvider ) {
  $stateProvider.state( 'about', {
    url: '/about',
    views: {
      "main": {
        controller: 'AboutCtrl',
        templateUrl: 'about/about.tpl.html'
      }
    },
    data: {
      title: "About"
    }
  });
})

.controller( 'AboutCtrl', function AboutCtrl( $scope, $state ) {
  console.log($state.get('about'));
  console.log($state.current);
  $scope.title = $state.current.data.title;
})

;

以下是about.spec.js中的测试代码(Jasmine):

describe( 'AboutCtrl', function() {
  var $scope, createController;

  beforeEach( module( 'ngBoilerplate.about' ) );

  beforeEach( inject( function( $controller, $rootScope, $state, $stateParams) {
    $scope = $rootScope.$new();
    createController = function() {
      $state.transitionTo('about', {});
      $rootScope.$digest();
      return $controller( 'AboutCtrl', { $scope: $scope, $state: $state });
    };
  }));

  it( 'should have title for about set', inject( function() {
    var controller = createController();
    expect($scope.title).toEqual('About');
  }));

});

这会产生结果:

LOG: Object{url: '/about', views: Object{main: Object{controller: ..., templateUrl: ...}}, data: Object{title: 'About1'}, name: 'about'}
LOG: Object{name: '', url: '^', views: null, abstract: true}
Chrome 29.0.1547 (Linux) AboutCtrl should have title for about set FAILED
    TypeError: Cannot read property 'title' of undefined

这表明状态正常,但由于某种原因它没有改变,保持在大致初始化的状态。再说一遍:在真实应用环境中调用此代码时,会显示正确填充的$state.current,其中包含所有数据等。

我查看了ui-router's tests,看起来他们做的完全相同($q.flush()是装饰的$rootScope.$digest()),所以我想这应该有效。

任何提示? (到目前为止,我对所有角色都有一点点菜鸟。)

2 个答案:

答案 0 :(得分:2)

您是否考虑在$rootScope.$apply()方法中使用$rootScope.$digest()代替createController

答案 1 :(得分:0)

请记住,ui路由器将初始化您的控制器并将范围对象注入其中,而在此测试中,您实例化您自己的控制器传递您自己的范围对象。您的控制器与ui路由器实例化的控制器不同,因此它们的范围对象也是不同的引用 我想如果你需要“单元测试”一个ui-router,那么只测试状态参数,但不测试控制器内的范围对象。如果需要测试作用域对象,请为控制器创建单元测试。