punkbit
punkbit

Reputation: 7717

angularjs 1 and jasmine, service promise testing

I'm trying to figure out how to test a service promise using karma + jasmine but without success. So far this is what I did with the result errors:

PhantomJS 2.1.1 (Mac OS X 0.0.0) The FetchData service should fetch data FAILED
    Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

fetchData service:

module.exports = function($http) {
   return {
        getFoo: function(id) {
             return $http.get('https://api/' + id)
                       .then(function(result) {
                            return result.data;
                        });
        }
   }
};

test:

describe('The FetchData service', function() {

  var dataFetcher;

  beforeEach(angular.mock.module("myApp"))

  beforeEach(inject(function(_dataFetcher_) {
    dataFetcher = _dataFetcher_;
  }));

  it('should fetch data', function(done) {

    var testData = function(res) {
      expect(res.success).toBe(true);
    };

    var failTest = function(error) {
      expect(error).toBeUndefined();
    };

    dataFetcher.getFoo(id)
      .then(testData)
      .catch(failTest);

  });
});

I wonder if there's something that I might be missing that can help me understand this,

Thanks!

Upvotes: 3

Views: 107

Answers (2)

punkbit
punkbit

Reputation: 7717

This is the solution I got this far, based on the actual Angularjs docs.

I hope it's self-explanatory (update based in @mehndra's answer and tips):

describe('The FetchData service', function() {

    var dataFetcher, $httpBackend;

    beforeEach(angular.mock.module("myApp"));

    beforeEach(inject(function(_dataFetcher_, _$httpBackend_) {
        dataFetcher = _dataFetcher_;
        $httpBackend = _$httpBackend_;
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should fetch data', function () {

        var status, data,
            pid = 2140,
            api = 'https://api';

        function successHandler(res){
            status = 'success';
            data = res.data;
            expect(res.success).toEqual(true);
            expect(status).toEqual('success');
        }

        function errorHandler(){
            status = 'error'
        }

        $httpBackend
         .when('GET', api + '/' + pid)
         .respond({ success: true });

        $httpBackend
         .when('GET', api + '/' + pid)
         .respond(500, 'An error has occured.');

        dataFetcher.get(pid).then(successHandler, errorHandler);

        $httpBackend.flush();

    });

});

Upvotes: 0

Mahendra Singh
Mahendra Singh

Reputation: 308

You need to inject the $httpBackend service in your tests to mock the $http service.

Then you need to call $httpBackend.flush to mock the actual HTTP call. Please check the angular docs for example.

Edit:

it('should fetch data', function () {

  var status, data;
  function successCB(response){
     status = 'success';
     data = response.data;
  }
  function errorCB(){
     status = 'error'
  }
  //only pass the success and error callbacks here
  dataFetcher.get(1).then(successCB, errorCB);

  // you need to stop it    
  $httpBackend.flush();

  //assert for success
  $httpBackend
     .when('GET', 'https://api/1')
     .respond(200, {foo:'bar'});

  expect(status).toEqual('success');
  expect(data).toEqual({foo: 'bar'});

  //assert for error
  $httpBackend
     .when('GET', 'https://api/1')
     .respond(500, 'An error has occured.');

  expect(status).toEqual('success');

});

Upvotes: 1

Related Questions