1

I'm writing unit tests against my js controller that initiates an http call through resource -> service. I need to mock the http call and get into response.then of initialCompetitions method (which never happens)

controller.js

class Controller {
    constructor(
        this.competitions = [];
    )

    $onInit() {
        this.initialCompetitions();
    }

    initialCompetitions = function() {
        let response = this.service.allCompetitions();
        var vm = this;
        response.then(function(value) {
            vm.competitions = value.data;
        });
    };
}
export default Controller;

service.js

class Service {
    allCompetitions = function () {
        return this.competitionResource.all();
    };
}
export default Service;

competitionResource.js

class CompetitionResource {
    constructor($http, $q) {
        this.$http = $http;
        this.apiUrlAll = 'path to api';
        this.$q = $q;
    }

    all = function() {
        var defer = this.$q.defer();

        this.$http({
            url: this.apiUrlAll,
            method: 'GET'
        })
        .then(function(response) {
            defer.resolve(response);
        },
        function(response) {
            defer.reject(response);
        });

        return defer.promise;
    }
}
export default CompetitionResource;

Unit test spec file:

describe('unit test', () => {
    let $rootScope, $location, $scope, $compile, controller, $q, mockData, service;

    mockData = {
        // data to mock
    };

    beforeEach(inject(($injector) => {
        $rootScope = $injector.get('$rootScope');
        $scope = $rootScope.$new();
        $location = $injector.get('$location');
        $compile = $injector.get('$compile');
        $q = $injector.get('$q');
    }));

    beforeEach(() => {
        service = {
            allCompetitions: function() {
                var deferred = $q.defer();
                deferred.resolve(mockCompetitionsData);
                return deferred.promise;
            }
        };
        controller = new Controller();
    });

    describe('initialCompetitions()', () => {

    it('should populate competitions', () => {

        expect(controller.competitions).to.be.empty;
        controller.initialCompetitions();
        expect(controller.competitions).to.not.be.empty; // fails because competitions are still empty

    });

});

});

expect(controller.competitions).to.not.be.empty; fails because competitions is still an empty array []

I suspect that I need to mock the promise in some different way but can't figure out how.

Seva Kalashnikov
  • 4,262
  • 2
  • 21
  • 36
  • What's with the [deferred anti-pattern](http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it)? `$http` already returns a promise – Phil Sep 27 '16 at 00:42
  • In any case, you need to trigger a digest cycle in your test in order for any promises to resolve. You can do this via `$rootScope.$apply()` or `$rootScope.$digest()` – Phil Sep 27 '16 at 00:44
  • Thanks @Phil, this was exactly what I was looking for. – Seva Kalashnikov Sep 27 '16 at 16:10

0 Answers0