Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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'
                },
            }
        })
  • If my view is [email protected] then how can I test that my controller is TagsCtrl, my controllerAs value is vm etc??

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

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

Any help is appreciable. Thanks

like image 330
shreyansh Avatar asked Mar 06 '16 07:03

shreyansh


Video Answer


2 Answers

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>
like image 173
TwitchBronBron Avatar answered Oct 11 '22 11:10

TwitchBronBron


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'
like image 24
eHx Avatar answered Oct 11 '22 12:10

eHx