Jasmine test for ajax request that returns a promise

I am new to Angular testing.

I am trying to test a simple method in a service that receives some data via an ajax call and returns a promise using Jasmine.

So far, very unfortunate.

This is the method I am testing:

function getDefaultFibonnacci() {
        var deferred = $q.defer();

        $http({ method: 'GET', url: '/api/fibonnacci/get' })
            .success(function (data) {
                deferred.resolve(data);
            })
            .error(function (data, status) {
                deferred.reject(status);
            });

        return deferred.promise;
    }

      

This is my test code: (Please note that all other tests pass separately from 'should return 0,1,1,2,3'

describe('datacontext', function () {
    var $httpBackend;
    var $rootScope;
    var datacontext;
    var $q;

    beforeEach(function () {
        module('app');
        inject(function (_$httpBackend_, _$rootScope_, _$q_, _datacontext_) {
            $httpBackend = _$httpBackend_;
            $rootScope = _$rootScope_;
            datacontext = _datacontext_;
            $q = _$q_;
        });
    });

    it('should have a getDefaultFibonnacci() function', function () {
        expect(angular.isFunction(datacontext.getDefaultFibonnacci)).toBe(true);
    });

    it('should return a promise', function () {
        expect(datacontext.getDefaultFibonnacci().then).toBeDefined();
    });

    it('should return 0,1,1,2,3', function () {
        var sequence = '123';

        $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
        $httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

        var deferred = $q.defer();
        var promise = deferred.promise;

        promise.then(function (response) {
            sequence = response.success;
        });

        datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });

        $rootScope.$digest();

        expect(sequence).toEqual('0,1,1,2,3');
    });
});

      

Thank you guys for all your comments. I learned a lot from this exercise.

This is the code I ended up with for passing the test.

function getDefaultFibonnacci() {
        return $http({ method: 'GET', url: '/api/fibonnacci/get' });
    }

it('should return 0,1,1,2,3', function () {
        var sequence;

        $httpBackend.whenGET('app/dashboard/dashboard.html').respond('');

        $httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');

        datacontext.getDefaultFibonnacci().then(function (data) {
            sequence = data.data;
        });

        $httpBackend.flush();

        expect(sequence).toEqual('0,1,1,2,3');
    });

      

+3


source to share


3 answers


$httpBackend

has a method for this reason. flush()

flush()

simulates the response of an HTTP server, so it calls your permission $http.get()

. Until you call it flush()

, nothing will happen (the server hasn't responded yet).

As such, replace your $rootScope.digest()

code with $httpBackend.flush()

and work from there.

Plus, you can save a lot of effort by understanding that the methods themselves $http

return promises.

It:

function getDefaultFibonnacci() {
    var deferred = $q.defer();

    $http({ method: 'GET', url: '/api/fibonnacci/get' })
        .success(function (data) {
            deferred.resolve(data);
        })
        .error(function (data, status) {
            deferred.reject(status);
        });

    return deferred.promise;
}

      



You can simplify the following:

function getDefaultFibonnacci() {

    return $http({ method: 'GET', url: '/api/fibonnacci/get' })

}

      

And let's do the same.

Finally, you don't need another promise in your test. This is enough (remove all reference to $q

and defer and put this directly after the code $httpBackend.when(...

):

datacontext.getDefaultFibonnacci()
.then(function (data) { 
    sequence = data;
});

      

+4


source


Are you expecting the {success: "0,1,1,2,3"} object as a response from the http service? You use response.success

when a promise is resolved

promise.then(function (response) {
            sequence = response.success;
        });

      

whereas you are returning the string '0,1,1,2,3'

$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

      



Also, I can see from the code that you don't need to create another promise to test your method.

Try the following:

it('should return 0,1,1,2,3', function () {
        var sequence = '123';

        $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
        $httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

        datacontext.getDefaultFibonnacci().then(function (data) { sequence = data; });

        $rootScope.$digest();

        expect(sequence).toEqual('0,1,1,2,3');
    });

      

+1


source


The most important thing you forgot to do is call $httpBackend.flush()

at some point after making queries before using the data.

Also, you don't need to create an additional promise.

it('should return 0,1,1,2,3', function () {
    var sequence;

    // Use the shorthand method whenGET
    $httpBackend.whenGET('app/dashboard/dashboard.html').respond('');

    // We should probably test that this request is actually made, so use expect<method>
    $httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');

    // Leave out the extra promise code.
    // var deferred = $q.defer();
    // var promise = deferred.promise;

    // promise.then(function (response) {
    //     sequence = response.success;
    // });

    // datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });

    datacontext.getDefaultFibonnacci().then(function (response) {
        sequence = response.success;
    });

    $httpBackend.flush(); // Flush the backend. Important!
    // $rootScope.$digest(); // I don't think this is necessary.

    expect(sequence).toEqual('0,1,1,2,3');
});

      

The html template will not be called if you have customized your application

+1


source







All Articles