0

I have the following controller

app.controller('NavController', ['$rootScope', '$scope', 'api', function($rootScope, $scope, $location, auth, api) {
    $scope.load = function() {
        return api.get('/location').success(function(data) {
            $rootScope.locations = data;
        }).error(function(data) {
            console.log('load error');
        });
    };
}]);

And this is the unit test I have written for it

describe('Navigation Controller Test', function() {

    beforeEach(module('app'));

    var controller, scope, rootScope, httpBackend;

    beforeEach(inject(function(_$controller_, _$rootScope_, $httpBackend) {
        var $controller = _$controller_;
        rootScope = _$rootScope_;
        scope = rootScope.$new();
        httpBackend = $httpBackend;
        controller = $controller('NavController', {
            $rootScope: rootScope,
            $scope: scope,
        });

        apiRequestHandler = httpBackend.when('GET', '/api/v2/location')
            .respond({userId: 'userX'});

    }));

    afterEach(function() {
        httpBackend.verifyNoOutstandingExpectation();
        httpBackend.verifyNoOutstandingRequest();
    });

    describe('load()', function() {
        it('should have locations when successful', function() {
            httpBackend.expectGET('/api/v2/location');
            scope.load();
            expect(rootScope.locations).toEqual("{userId: 'userX'}");
            httpBackend.flush();
        });
    });
});

The current issue I'm having is that rootScope.locations is undefined even after calling the scope.load() function. I'm not too sure why this is but the closest post I seem to have found is this one which I think might be related to my problem but I'm not quite certain.

I did a console.log($rootScope.locations) in the controller when the get request is successful and it had the correct output however I'm stumped on how to get it to appear the same for this test.

1 Answer 1

1

You shouldn't mess with rootScope in controller. You controller should work only with $scope and in order to have the jasmine test working, you should have beforeEach as follows:

var controller, scope, httpBackend;

beforeEach(inject(function(_$controller_, _$rootScope_, $httpBackend) {
    var $controller = _$controller_;
    scope = rootScope.$new();
    httpBackend = $httpBackend;
    controller = $controller('NavController', {
        $scope: scope,
        //authentication dependency and so on
    });

    ...

}));

and you controller :

 app.controller('NavController', function($scope, api) {
     $scope.load = function() {
         return api.get('/location').success(function(data) {
             $scope.locations = data;
         }).error(function(data) {
         console.log('load error');
    });
};
});

Edit: Also the test flow should be:

it('should have locations when successful', function() { 
  scope.load(); 
  httpBackend.expectGET('/api/v2/location'); 
  httpBackend.flush(); 
  expect(rootScope.locations).toEqual("{userId: 'userX'}"); 
}); 

You need first to call your function, than to have expectations for http backend, next flush and only afterwards to do the verifications. Also httpBackend can be used only if in controller you use $http, not a different third party ajax calls provider.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your response. I've modified it so that the controller uses scope however I seem to run into the same error of scope.locations still being undefined.
can you make sure your data is not null? Also do you know this by the fact that jasmine test is failing or you debug the controller and it is empty?
I see that there is an issue in your test flow. It should be: it('should have locations when successful', function() { scope.load(); httpBackend.expectGET('/api/v2/location'); httpBackend.flush(); expect(rootScope.locations).toEqual("{userId: 'userX'}"); }); You need first to call your function, than to have expectations for http backend, next flush and only afterwards to do the verifications. Also httpBacken can be used only if in controller you use http, not a different third party ajax calls provider.
I've verified that the data is not null. I've checked the Jasmine test and I've debugged the controller. It seems to be working when I do a console.log($scope.locations) from the controller.
Ah that fixed it! Thank you so much. If you don't mind, could you please explain why that made the test pass?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.