Search code examples
javascriptangularjsjasminengmocke2e

How test controller who gets data from promise object


I have controller who gets data from promise object.

Controller look like this:

MyApp.controller("BookListController", ["$scope", "BookListModel","LibraryService", function($scope, BookListModel, LibraryService) {
    LibraryService.getLibraryData().then(function(result) {
        $scope.books = BookListModel.createBookList(result.bookList.data, result.authorList.data, result.publisherList.data);
    });
}]);

This is my factory who gets data from REST service.

MyApp.factory("LibraryService", function($http, $q) {
    var service = {};
    var libraryDataPromise = $q.defer();

    $q.all({
        books : $http.get("http://localhost:8080/library/service/books"),
        authors : $http.get("http://localhost:8080/library/service/authors"),
        publishers : $http.get("http://localhost:8080/library/service/publishers")
    }).then(function(response) {
        libraryDataPromise.resolve({
            bookList : response.books,
            authorList : response.authors,
            publisherList : response.publishers
        });
    });

    service.getLibraryData = function() {
        return libraryDataPromise.promise;
    }

    return service;
});

Ok, that is all. Now is time to show my test who I wrote.

describe("Book_App Controllers", function() {

describe("BookListController Test", function() {
    var BookListModelMock, LibraryServiceMock, scope = {}, controller
        ,deferred, promise;

    beforeEach(function() {
        module("MyApp");
        BookListModelMock = new function() {
            this.createBookList = function(a, b, c) {
                return [{},{},{}];
            };
        };
    });

    beforeEach(inject(function($rootScope, $controller ) {
        scope = $rootScope.$new();
        controller = $controller("BookListController",
            {$scope : scope, BookListModel : BookListModelMock});
    }));

    beforeEach(inject(function($q) {
        deferred = $q.defer();
        promise = deferred.promise;
        deferred.resolve([
            { data : [{}, {}, {}]}
        ])

        LibraryServiceMock = function() {
            var service = {};

            service.getLibraryData = function() {
                return promise;
            }
        };
    }));

    it("should contains three books", inject(function($rootScope) {
        $rootScope.$apply();
        expect(scope.books.length).toBe(3);
    }));
});

});

When I run test, the Jasmine throw: Error: Unexpected request: GET http://localhost:8080/library/service/books No more request expected

I know what means this problem but I don't know what resolve it. Should I mock $http? I read how testing promise and defer but tutorial describe how testing functions who contains $q operations and not describe how testing functions who are dependent from functions who contains $q operations.


Solution

  • Your LibraryServiceMock isn't being used. You need to create your mock before creating your controller and then use it in the same way you provide the BookListModelMock to the new controller.

    When you write your LibraryService tests, you can use $httpBackend.expect() to mock the requests: https://docs.angularjs.org/api/ngMock/service/$httpBackend