简体   繁体   English

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

[英]Angular ui router unit testing (states to urls)

I'm having some trouble unit testing the router in my application, which is built on the Angular ui router. 我在我的应用程序中对路由器进行单元测试时遇到了一些麻烦,该应用程序是在Angular ui路由器上构建的。 What I want to test is whether state transitions change the URL appropriately (there will be more complicated tests later, but this is where I'm starting.) 我想测试的是状态转换是否适当地改变了URL(稍后会有更复杂的测试,但这是我开始的地方。)

Here is the relevant portion of my application code: 这是我的应用程序代码的相关部分:

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

And the testing code: 和测试代码:

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");
  })
})

Similar questions on Stackoverflow (and the official ui router test code) suggest wrapping the $state.go call in $apply should be enough. 关于Stackoverflow(以及官方的ui路由器测试代码)的类似问题建议在$ apply中包装$ state.go调用应该足够了。 But I've done that and the state is still not updating. 但我已经这样做了,州仍然没有更新。 $state.current.name remains empty. $ state.current.name保持为空。

Been having this issue as well, and finally figured out how to do it. 一直有这个问题,最后想出怎么做。

Here is a sample state: 这是一个示例状态:

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();
            }]
        }
    });
}]);

The unit test below will cover testing the URL w/ params, and executing the resolves which inject its own dependencies: 下面的单元测试将涵盖测试带有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');
  });
});

If you want to check only the current state's name it's easier to use $state.transitionTo('splash') 如果你只想检查当前状态的名称,那么更容易使用$state.transitionTo('splash')

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

I realize this is slightly off topic, but I came here from Google looking for a simple way to test a route's template, controller, and URL. 我意识到这有点偏离主题,但我从谷歌来到这里寻找一种简单的方法来测试路线的模板,控制器和URL。

$state.get('stateName')

will give you 会给你

{
  url: '...',
  templateUrl: '...',
  controller: '...',
  name: 'stateName',
  resolve: {
    foo: function () {}
  }
}

in your tests. 在你的测试中。

So your tests could look something like this: 所以你的测试看起来像这样:

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

For a state that without resolve : 对于没有resolvestate

// TEST DESCRIPTION
describe('UI ROUTER', function () {
    // TEST SPECIFICATION
    it('should go to the state', function () {
        module('app');
        inject(function ($rootScope, $state, $templateCache) {
            // When you transition to the state with $state, UI-ROUTER
            // will look for the 'templateUrl' mentioned in the state's
            // configuration, so supply those templateUrls with templateCache
            $templateCache.put('app/templates/someTemplate.html');
            // Now GO to the state.
            $state.go('someState');
            // Run a digest cycle to update the $state object
            // you can also run it with $state.$digest();
            $state.$apply();

            // TEST EXPECTATION
            expect($state.current.name)
                .toBe('someState');
        });
    });
});

NOTE:- 注意:-

For a nested state we may need to supply more than one template. 对于嵌套状态,我们可能需要提供多个模板。 For ex. 对于前者 if we have a nested state core.public.home and each state , ie core , core.public and core.public.home has a templateUrl defined, we will have to add $templateCache.put() for each state's templateUrl key:- 如果我们有一个嵌套状态core.public.home并且每个state ,即corecore.publiccore.public.home都定义了templateUrl ,我们将不得不为每个状态的templateUrl键添加$templateCache.put() : -

$templateCache.put('app/templates/template1.html'); $templateCache.put('app/templates/template2.html'); $templateCache.put('app/templates/template3.html');

Hope this helps. 希望这可以帮助。 Good Luck. 祝好运。

You could use $state.$current.locals.globals to access all resolved values (see the code snippet). 您可以使用$state.$current.locals.globals来访问所有已解析的值(请参阅代码段)。

 // Given $httpBackend .expectGET('/api/users/123') .respond(200, { id: 1, email: 'test@email.com'); // When $state.go('users.show', { id: 123 }); $httpBackend.flush(); // Then var user = $state.$current.locals.globals['user'] expact(user).to.have.property('id', 123); expact(user).to.have.property('email', 'test@email.com'); 

In ui-router 1.0.0 (currently beta) you could try to invoke $resolve.resolve(state, locals).then((resolved) => {}) in the specs. 在ui-router 1.0.0(目前是测试版)中,您可以尝试在规范中调用$resolve.resolve(state, locals).then((resolved) => {}) For instance https://github.com/lucassus/angular-webpack-seed/blob/9a5af271439fd447510c0e3e87332959cb0eda0f/src/app/contacts/one/one.state.spec.js#L29 例如https://github.com/lucassus/angular-webpack-seed/blob/9a5af271439fd447510c0e3e87332959cb0eda0f/src/app/contacts/one/one.state.spec.js#L29

If you're not interested in anything in the content of the template, you could just mock $templateCache: 如果您对模板内容中的任何内容不感兴趣,您可以模拟$ templateCache:

beforeEach(inject(function($templateCache) {
        spyOn($templateCache,'get').and.returnValue('<div></div>');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM