Oscar
Oscar

Reputation: 1147

How to unit test after promise of a controller in AngularJS?

I have a controller that has a callback inside:

angular.module('controllers').controller('headerController', headerController);

function headerController(headerService) {
    var self = this;

    headerService.getHeaderContentData()
        .then(function(response) {
            self.contentData = response.content;
        });
}

My problem is that I need to check the value of contentData in an unit test. The idea is when I call expect(ctrl.contentData).to.be.defined passes the test, but the value of ctrl.contentData is undefined. Is there a way to test this behavior (test the self.contentData when the callback occurs)?

Current unit test:

describe("controller", function() {
    var controller, $httpBackend;

    beforeEach(angular.mock.inject(function($injector, _$httpBackend_){
        var $controller = $injector.get('$controller');
        $httpBackend = _$httpBackend_;

        var $scope = {};
        $httpBackend.when('GET', '/data/header.content.json')
                    .respond(require('../../mock-data/header.content.json'));
        var controller = $controller('headerController', { $scope: $scope });
        $httpBackend.flush();
    }));

    it("should have contentData property populated", function() {
        expect(controller.contentData).to.exist; // <- here fails: current value is undefined
    });
});

My unit testing framework is jasmine

Upvotes: 1

Views: 1470

Answers (1)

ronapelbaum
ronapelbaum

Reputation: 1797

Since your controller doesn't use $hhtp, there is no reason to handle it in the test. The proper way to test your headerController is to mock your headerService.

Mock a service:

beforeEach(module(function($provide) {
    mockService = jasmine.createSpyObj('headerService', ['getHeaderContentData']);
    $provide.value('headerService', mockService);
}));

beforeEach(inject(function($controller) {
    ctrl = $controller('headerController');
}));

Now, you need to mock getHeaderContentData() to return a promise - use $q.

Mock service method:

it('should change after promise resolved', inject(function($q, $rootScope) {
    //create promise
    deferred = $q.defer();

    //mock service response (foc controller's constructor)
    mockService.getHeaderContentData.and.returnValue(deferred.promise);

    //call init()
    ctrl.init();

    expect(ctrl.contentData).toBeNull();

    deferred.resolve('Hello World');

    //not yet...
    expect(ctrl.contentData).toBeNull();

    //from angular $q dosumentation:
    //"it's important to know that the resolution of promises is tied to the digest cycle"
    $rootScope.$apply();

    //now!
    expect(ctrl.contentData).toBe('Hello World');

}));

see jsFiddle

Upvotes: 2

Related Questions