Angular ui路由器单元测试(状态到网址)

Ter*_*nce 79 javascript unit-testing angularjs angular-ui-router

我在我的应用程序中对路由器进行单元测试时遇到了一些麻烦,该应用程序是在Angular ui路由器上构建的.我想测试的是状态转换是否适当地改变了URL(稍后会有更复杂的测试,但这是我开始的地方.)

这是我的应用程序代码的相关部分:

angular.module('scrapbooks')
 .config( function($stateProvider){
    $stateProvider.state('splash', {
       url: "/splash/",
       templateUrl: "/app/splash/splash.tpl.html",
       controller: "SplashCtrl"
    })
 })
Run Code Online (Sandbox Code Playgroud)

和测试代码:

it("should change to the splash state", function(){
  inject(function($state, $rootScope){
     $rootScope.$apply(function(){
       $state.go("splash");
     });
     expect($state.current.name).to.equal("splash");
  })
})
Run Code Online (Sandbox Code Playgroud)

关于Stackoverflow(以及官方的ui路由器测试代码)的类似问题建议在$ apply中包装$ state.go调用应该足够了.但我已经这样做了,州仍然没有更新.$ state.current.name保持为空.

小智 124

一直有这个问题,最后想出怎么做.

这是一个示例状态:

angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
    $stateProvider.state('myState', {
        url: '/state/:id',
        templateUrl: 'template.html',
        controller: 'MyCtrl',
        resolve: {
            data: ['myService', function(service) {
                return service.findAll();
            }]
        }
    });
}]);
Run Code Online (Sandbox Code Playgroud)

下面的单元测试将涵盖测试带有params的URL,并执行注入其自身依赖项的结果:

describe('myApp/myState', function() {

  var $rootScope, $state, $injector, myServiceMock, state = 'myState';

  beforeEach(function() {

    module('myApp', function($provide) {
      $provide.value('myService', myServiceMock = {});
    });

    inject(function(_$rootScope_, _$state_, _$injector_, $templateCache) {
      $rootScope = _$rootScope_;
      $state = _$state_;
      $injector = _$injector_;

      // We need add the template entry into the templateCache if we ever
      // specify a templateUrl
      $templateCache.put('template.html', '');
    })
  });

  it('should respond to URL', function() {
    expect($state.href(state, { id: 1 })).toEqual('#/state/1');
  });

  it('should resolve data', function() {
    myServiceMock.findAll = jasmine.createSpy('findAll').and.returnValue('findAll');
    // earlier than jasmine 2.0, replace "and.returnValue" with "andReturn"

    $state.go(state);
    $rootScope.$digest();
    expect($state.current.name).toBe(state);

    // Call invoke to inject dependencies and run function
    expect($injector.invoke($state.current.resolve.data)).toBe('findAll');
  });
});
Run Code Online (Sandbox Code Playgroud)

  • @Philip我面临同样的问题`$ state.current.name`是空字符串. (5认同)
  • 我按照上面的注释中提到的`andReturn`进行了调整.但是,我的$ state.current.name返回一个空字符串.谁知道为什么? (2认同)

小智 18

如果您只想检查当前状态的名称,则更容易使用 $state.transitionTo('splash')

it('should transition to splash', inject(function($state,$rootScope){
  $state.transitionTo('splash');
  $rootScope.$apply();
  expect($state.current.name).toBe('splash');
}));
Run Code Online (Sandbox Code Playgroud)

  • 为了简单起见,我发现这个答案是最容易接受的.测试很好,但是必须编写一个比我的整个ui-route定义更长的测试只是为了测试单个端点,这只是低效的方法.无论如何,我都在投票 (4认同)

dch*_*cke 15

我意识到这有点偏离主题,但我从谷歌来到这里寻找一种简单的方法来测试路线的模板,控制器和URL.

$state.get('stateName')
Run Code Online (Sandbox Code Playgroud)

会给你

{
  url: '...',
  templateUrl: '...',
  controller: '...',
  name: 'stateName',
  resolve: {
    foo: function () {}
  }
}
Run Code Online (Sandbox Code Playgroud)

在你的测试中.

所以你的测试看起来像这样:

var state;
beforeEach(inject(function ($state) {
  state = $state.get('otherwise');
}));

it('matches a wild card', function () {
  expect(state.url).toEqual('/path/to/page');
});

it('renders the 404 page', function () {
  expect(state.templateUrl).toEqual('views/errors/404.html');
});

it('uses the right controller', function () {
  expect(state.controller).toEqual(...);
});

it('resolves the right thing', function () {
  expect(state.resolve.foo()).toEqual(...);
});

// etc
Run Code Online (Sandbox Code Playgroud)