Nick B
Nick B

Reputation: 715

How to test a service function in Angular that returns an $http request

I have a simple service that makes an $http request

angular.module('rootApp')
    .factory('projectService', ['$http', function ($http) {

        return {
            getProject: getProject,
            getProjects: getProjects,
        };

        function getProject(id) {
            return $http.get('/projects.json/', { 'params': { 'id': id }});
        }
    }]);

I'm wondering how can I test this simply and cleanly? Here's what I have so far in my test.

describe("Root App", function () {

var mockGetProjectResponse = null,
    $httpBackend = null;

beforeEach(module('rootApp'));

beforeEach(inject(function (_$httpBackend_, projectService) {
    $httpBackend = _$httpBackend_;
    $httpBackend.when('GET', '/projects.json/?id=1').response(mockGetProjectResponse);
}));

describe("should get projects successfully", inject(function (projectService) {

    it("should return project", function () {

        // I essentially want to do something like this (I know this isn't the right format).. but:             

        //expect(projectService.getProject(1)).toBe(mockGetProjectResponse);

    });
}));

I want to avoid explicitly calling $http.get(...) in my test, and rather stick to calling the service function, i.e. projectService.getProject(1). What I'm stuck on is not being able to do something like this:

projectService.getProject(1)
    .success(function (data) {
                expect(data).toBe(whatever);
            })
            .error(function () {

            });

Since there's 'no room' to call $httpBackend.flush();

Any help would be much appreciated. Thanks.

Upvotes: 2

Views: 110

Answers (1)

Estus Flask
Estus Flask

Reputation: 222379

The usual recipe for testing promises (including $http) is

it("should return project", function () {
    var resolve = jasmine.createSpy('resolve');
    projectService.getProject(1).then(resolve);
    expect(resolve).toHaveBeenCalledWith(mockGetProjectResponse);
});

A good alternative is jasmine-promise-matchers which eliminates the need for spy boilerplate code.

Here's a plunker that demonstrates both of them.

Generally the one may want to keep the methods that make $http calls as thin as possible and stub them instead, so mocking $httpBackend may not be required at all.

In current example the spec tests literally nothing and can be omitted and left to e2e tests if the code coverage isn't an end in itself.

Upvotes: 2

Related Questions