5

I have state defined in my angular module "moduleB" as follows

$stateProvider
                .state('stateB', {
                    parent: 'stateA',
                    abstract: true,
                    templateUrl : baseUrl+'/templates/stateB.html'
                })
                .state('stateB.details', {
                    url: '/stateB/details/:param1/:param2',
                    resolve : {
                        value3 : ['$localStorage', '$stateParams', function($localStorage, $stateParams){
                            return $localStorage.value3[$stateParams.param1];
                        }]
                    },
                    views : {
                        'view1' : {
                            templateUrl : baseUrl+'/templates/view1.html',
                            controller: 'View1Ctrl'
                        },
                        'view2' : {
                            templateUrl : baseUrl+'/templates/view2.html',
                            controller : 'View2Ctrl'
                        }
                    }
                })

I would like to write unit test for the "resolve" and here is my jasmine unit test.

var rootScope, state, injector,  mockLocalStorage, httpBackend;
beforeEach(module('moduleB'));
 beforeEach(inject(function($rootScope, $state, $injector, $localStorage, $httpBackend) {
            rootScope = $rootScope;
            state = $state;
            injector = $injector;
            httpBackend = $httpBackend;
            mockLocalStorage = $localStorage;
        }));

it('should should resolve the data', function() {
            mockLocalStorage.value3 = {};
            mockLocalStorage.value3["1234567890"] = 'resolved-data';
            state.go('stateB.details', {
                                            "param1" : "1234567890",
                                            "param2" : true
                                      });
            rootScope.$digest();


            console.log('state', state);
            expect(state.current.name).toBe('stateB.details');
             expect(injector.invoke(state.current.resolve.value3)).toBe('resolved-data');

        });

1) console.log('state', state) ==> prints 'state', Object{params: Object{}, current: Object{name: '', ........}

2) expect(state.current.name).toBe('stateB.details') ==> fails with error Expected '' to be 'stateB.details'.

3) expect for resolve ==> fails with error TypeError: 'undefined' is not an object (evaluating 'state.current.resolve.value3')

Can anyone help in pointing what am I missing?

UPDATE:

I modified my test to have assertions in the success block of the promise. It passes the test even when the assertions are false.

it('should resolve the data', function() {
            mockLocalStorage.value3 = {};
            mockLocalStorage.value3["1234567890"] = 'resolved-data';
            state.go('stateB.details', {
                                            "param1" : "1234567890",
                                            "param2" : true
                                      }).then(function() {
                                                    console.log('state', state);
             expect(state.current.name).toBe('stateB.details');                                         expect(injector.invoke(state.current.resolve.value3)).toBe('resolved-data2'); 
                                             });;
        });

This test passes and nothing is displayed for "console.log('state', state);" . And, my assertion for "resolved-data2" should fail as the expected value is "resolved-data".

user3701057
  • 395
  • 1
  • 6
  • 22
  • Can anyone help me with this issue? – user3701057 Apr 10 '15 at 16:26
  • How about doing something like `state.go('stateB.details', { ... }).then(function() { ... })`, or using the state change events? I don't think a single call to `$digest` cuts it in this case. – user1421750 Apr 13 '15 at 23:39
  • Can you give a little detailed example? With you approach, where should I check for the assertions with in the success block of the promise? where should I call the $digest? – user3701057 Apr 13 '15 at 23:44
  • Try putting the assertions immediately inside the callback for the promise. At this point the state should be fully resolved. Leave everything else as is. – user1421750 Apr 13 '15 at 23:59
  • I tried this and updated my question with the results. It passes the tests even when the assertions are false. Am I missing anything? Please take a look at the update. – user3701057 Apr 14 '15 at 17:23
  • Oh right, it slipped my mind that the test will just finish up at once like this. The state change needs to be resolved asynchronously. See this question http://stackoverflow.com/a/27673009/1421750 – user1421750 Apr 15 '15 at 01:46

1 Answers1

10

Finally, I fixed the problem. Here is the solution for any one who is interested in.

1) Import modules

beforeEach(module('stateA'));
   beforeEach(module('stateB'));
   beforeEach(module('ui.router'));

2)

beforeEach(module(


function($provide) {
            $provide.value('$localStorage', mockStorage = { value3: []});
            $provide.value('$stateParams', stateParams = { param1: 1234, param2: "true"});
        }));

3) unit test:

it('should go to stateB.details state and resolve the data', function() {
            mockStorage.assetInfo[stateParams.value3] = 'resolved-data';
            var s = state.get('stateB.details');
            expect(injector.invoke(s.resolve.value3)).toEqual('resolved-data');
        });
user3701057
  • 395
  • 1
  • 6
  • 22