Reputation: 9207
I am trying to write unit-test for ui-router's state and can not get it to work so that $state.current
would contain a correct state inside the controller after I call $state.transitionTo()
inside test.
This works in browser (where transitionTo
is called by ui-router
internally), but does not in unit-tests (using Karma) - where I call it explicitly.
Here's the code for the controller:
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;
})
;
And here is the test code (Jasmine) in about.spec.js
:
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');
}));
});
This produces the results:
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
Which shows that state is being inited OK, but it does not change for some reason, stays in a roughly initialized state. Again: this code when invoked in a real app environment shows the correctly filled $state.current
which has all the data etc.
I have looked at ui-router
's tests and it looks like they do exactly the same thing ($q.flush()
is a decorated $rootScope.$digest()
there), so I guess this should work.
Any hints? (I'm a bit noob with everything angular so far :)
Upvotes: 4
Views: 3845
Reputation: 583
Remember, the ui router will initialize your controller and will inject the scope object into it, while in this test, you instantiated your own controller passing your own scope object. Your controller is not the same with the one instantiated by the ui router, and hence their scope objects are different references too.
I guess if you need to "unit test" a ui-router then test only the state parameters, but not scoped objects inside the controller. If you need to test scoped objects, create a unit test for the controller.
Upvotes: 0
Reputation: 2220
Have you considered using $rootScope.$apply()
instead of $rootScope.$digest()
in the createController
method?
Upvotes: 2