efarley
efarley

Reputation: 8651

karma mock promise response

I have the following factory that I'd like to test:

angular
    .module('enigma.authFactory', [])    
    .factory('authFactory', authFactory);

authFactory.$inject = ['$http'];

function authFactory($http){
    function doesUserExist(email){
        return $http.post('/doesUserExist', email)
            .success(function(data){
                if(data !== 'user exists'){
                    return false;
                } else {
                    return true;
                }
            });
    }
}

So I wrote the following test:

describe('Auth Service Tests', function() {
    var $httpBackend, defer, doesUserExistReqHandler;

    beforeEach(inject(function(_$httpBackend_, $injector, $q) {
        $httpBackend = _$httpBackend_; 
        defer = $q.defer();
        doesUserExistReqHandler = $httpBackend.when('POST', '/doesUserExist').respond(defer.promise);
    }));

    describe('authFactory.doesUserExist()', function() {
        it('should return true is a user exists', function() {
            user = {
                email: '[email protected]'
            };
            $httpBackend.whenPOST('/doesUserExist', user).respond('user exists');
            var doesUserExist = authFactory.doesUserExist(user);
            $httpBackend.flush();
            expect(doesUserExist).toEqual(true);
        });
    });
});

I checked inside the authFactory.doesUserExist function and I am correctly getting the data set to 'user exists' which routes the function to return true. However in the unit test authFactory.doesUserExist is being set to the following object.

Expected Object({ $$state: Object({ status: 1, pending: undefined, value: Object({ data: Object({ $$state: Object({ status: 0 }) }), status: 200, headers: Function, config: Object({ method: 'POST', transformRequest: [ Function ], transformResponse: [ Function ], paramSerializer: Function, url: '/doesUserExist', data: Object({ email: '[email protected]' }), headers: Object({ Accept: 'application/json, text/plain, */*', Content-Type: 'application/json;charset=utf-8' }) }), statusText: '' }), processScheduled: false }), success: Function, error: Function }) to equal true.

I'm thinking the issue is that the test isn't resolving the promise properly and so I'm setting the res variable before authFactory.doesUserExist has returned true.

How would I go about fixing this?

Upvotes: 0

Views: 4067

Answers (1)

angmerica
angmerica

Reputation: 797

So a few things needs to happen to get your code to work with what you have.

Here is a demo http://plnkr.co/edit/4GvMbPJgc0HcJcgFZ4DL?p=preview

  1. Your service (factory) needs to return an object.
  2. You are not returning a promise after your $http post.
    • I recommend you use the $q service.

In the testing

  1. You need to import your module.
  2. Be sure to inject your service
  3. You should remove $httpBackend.when('POST', '/doesUserExist').respond(defer.promise); since it is not accomplishing anything and it is actually getting it confused in other $httpBackend.whenPost.
  4. You should be asserting the response data instead of the promise, because authFactory.doesUserExist(user) returns a promise.

Code:

var doesUserExist = authFactory.doesUserExist(user)  
  .then(function (data) {
    responseData = data;
  });

$httpBackend.flush();
expect(responseData).toEqual(true);

Upvotes: 1

Related Questions