shreyansh
shreyansh

Reputation: 1687

angularJS $stateProvider : How to unit test different views in UI-Router?

How can I unit test different views for the below scenario

.state('app.sr.product.upload', {
            name: 'upload',
            url: '/upload',
            data: {
                tags: [],
                userCommunities: []
            },
            views: {
                "[email protected]": {
                    templateUrl: 'views/upload/upload.html',
                    controller: 'UploadCtrl',
                    controllerAs: 'ul'
                },
                "[email protected]": {
                    templateUrl: 'views/tags/tags.html',
                    controller: 'TagsCtrl',
                    controllerAs: 'vm'
                },
                "[email protected]": {
                    templateUrl: 'views/user-community/user-community.html',
                    controller: 'UserCommunityCtrl',
                    controllerAs: 'ul'
                },
            }
        })

I searched for lot of docs and tutorials but didnt get it .

Any help is appreciable. Thanks

Upvotes: 6

Views: 4043

Answers (3)

eHx
eHx

Reputation: 181

If I'm not wrong, I think we missed the point of the initial question, which was

if my view is [email protected] then how can I test that my controller is TagsCtrl, my controllerAs value is vm etc??

and

How can I unit test if my state is app.sr.product.upload then data.tags=[], data.userCommunities=[] etc.

Here's how you can test these :

var $rootScope, $state, $injector, state;

beforeEach(inject(function(_$rootScope_, _$state_){
    $rootScope = _$rootScope_;
    $state = _$state_;
    state = $state.get('app.sr.product.upload');
}));

it('should have the correct data parameters', function () {

    expect(state.data.tags).toEqual('');
    expect(state.data.userCommunities).toEqual('');

});

it('should render the dashboard views with the right Controllers', function () {

    var product = state.views['[email protected]'];
    var tags= state.views['[email protected]'];
    var userCommunity = state.views['[email protected]'];

    expect(product.templateUrl).toEqual('views/upload/upload.html');
    expect(product.controller).toEqual('UploadCtrl');
    expect(product.controllerAs).toEqual('ul');

    // etc...

});

Also, in newer angular versions, you can just declare your controller like so:

controller: 'UploadCtrl as vm'

Upvotes: 1

TwitchBronBron
TwitchBronBron

Reputation: 3186

Try this on for size. I'm assuming you would be using jasmine for your tests, but the concept is the same for any testing framework.

When you run your test, first subscribe to the '$stateChangeSuccess' event and then navigate to that state. Once the event fires, check the toState values to see if they are what you expect them to be.

You can run the snippet to see the tests in action.

//write a unit test
describe('state changes', function() {
  beforeEach(module('app'));
  var $rootScope, $state;
  beforeEach(inject(function(_$rootScope_, _$state_) {
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $rootScope = _$rootScope_;
    $state = _$state_;
  }));


  it('loads page 1', function(done) {
    //wait for the state to change, then make sure we changed to the correct state
    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
      expect(toState.controller).toEqual('Controller1');
      done();
    });
    //navigate to the state
    $state.go('state1');
    //start a digest cycle so ui-router will navigate
    $rootScope.$apply();
  });

  it('loads page 2', function(done) {
    //wait for the state to change, then make sure we changed to the correct state
    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
      expect(toState.controller).toEqual('Controller2');
      done();
    });
    //navigate to the state
    $state.go('state2');
    //start a digest cycle so ui-router will navigate
    $rootScope.$apply();
  });

  it('loads page 3', function(done) {
    //wait for the state to change, then make sure we changed to the correct state
    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
      expect(toState.controller).toEqual('Controller3');
      done();
    });
    //navigate to the state
    $state.go('state3');
    //start a digest cycle so ui-router will navigate
    $rootScope.$apply();
  });
});

//set up some dummy controllers and some dummy states
angular.module('app', ['ui.router']).controller('Controller1', function() {
  this.message = 'Page 1';
}).controller('Controller2', function() {
  this.message = 'Page 2';
}).controller('Controller3', function() {
  this.message = 'Page 3';
}).config(function($stateProvider, $urlRouterProvider) {
  $urlRouterProvider.otherwise("/state1");

  $stateProvider.state('state1', {
    url: "/state1",
    controller: 'Controller1',
    controllerAs: 'vm',
    template: '<h1>{{vm.message}}</h1>'
  }).state('state2', {
    url: "/state2",
    controller: 'Controller2',
    controllerAs: 'vm',
    template: '<h2>{{vm.message}}</h2>'
  }).state('state3', {
    url: "/state3",
    controller: 'Controller3',
    controllerAs: 'vm',
    template: '<h3>{{vm.message}}</h3>'
  });
});
h1 {
  color: red;
}
h2 {
  color: blue;
}
h3 {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>

<script src="
https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<link rel="stylesheet" type="text/css" href="http://jasmine.github.io/2.0/lib/jasmine.css">
<script src="http://jasmine.github.io/2.0/lib/jasmine.js"></script>
<script src="http://jasmine.github.io/2.0/lib/jasmine-html.js"></script>
<script src="http://jasmine.github.io/2.0/lib/boot.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-mocks.js"></script>
<div ng-app="app">
  <a ui-sref="state1">State 1</a>
  <a ui-sref="state2">State 2</a>
  <a ui-sref="state3">State 3</a>
  <div ui-view></div>
</div>

Upvotes: 5

m1gu3l
m1gu3l

Reputation: 773

It's not something I would normally unit test. UI-Router itself is well covered by tests.

You'd do better with e2e (end-to-end) tests with Protractor. You simulate a click on a link, you expect url to be this, use expect number of elements in a list to be that etc.

But if you really need it:

  • locate root element of each view (f.e. by adding a specific class and using selectors)
  • you should be able to access scope and controller via angular.element wrapper methods

Upvotes: 0

Related Questions