1

I'm learning angularJS unit-testing and I'm struggling unit testing a basic "login" function on an "AuthenticationService" service.

The service method uses $q.defer() to set up a promise and then rejects or resolves it based on input.

How do I spy on or otherwise test that promise?

What is wrong with the below? The test fails - error is "undefined" rather than 'AuthenticationService.login - missing argument'

Hopefully it is obvious what I am trying to do, I can't really put it into words.

The Service

angular.module('moduleName').factory('AuthenticationService', function($q, $http) {
    var serviceObject = {
        login = function(credential, password) {
            var d = $q.defer();

              // check if any fields are missing
              if (!credential && !password || credential === '' || password === '') {
                d.reject('AuthenticationService.login - missing argument');
              } else {
                var sacho = {message: "I'm so confused"};
                d.resolve(sacho);
                }

               return d.promise;
            }
        }
    };

    return serviceObject;
});

The Test

describe('AuthenticationService', function()
{
  var scope, AuthenticationService, $httpBackend;

  beforeEach(inject(function($rootScope, _AuthenticationService_, _$httpBackend_) {
    scope = $rootScope.$new();
    AuthenticationService = _AuthenticationService_;
    MemberLookup = _MemberLookup_;
    $httpBackend = _$httpBackend_;
  }));

  describe('Logging In', function() {
    it('promise should be rejected if any fields are empty', function() {
      AuthenticationService.login('','').catch(function(error){
        expect(error).toEqual('AuthenticationService.login - missing argument');
      });
    });
  });
});

EDIT: AuthenticationService.login returns a promise.

The promise should be rejected if either of the credentials to the method are blank or missing.

In the test code (below) I have tried to write a test to see if the promise is rejected. The test inputs blank strings as arguments to the AuthenticationService.login method. The expected behaviour is the promise being rejected with the string 'AuthenticationService.login - missing argument'. However, running the test fails - Authentication.Service.login('','').catch's callback does not work as expected.

I have also tried using .then(null, callback).

How do I spy on the promise returned by AuthenticationService.login when given specific parameters?

rbutera
  • 153
  • 3
  • 15
  • i'm not sure what is the question here, can you please explain which code are you trying to test? – Liad Livnat Jul 13 '14 at 15:32
  • If there is nothing asynchronous there, you should not be using a promise in the first place. – Benjamin Gruenbaum Jul 13 '14 at 15:46
  • Liad Livnat: `AuthenticationService.login` returns a promise. The promise should be rejected if either of the credentials to the method are blank or missing. I have tried to write a test to see if the promise is rejected. The test inputs blank strings as arguments to the `login` method. The expected behaviour is the promise being rejected with a string. However, the test fails - `login('','').catch`'s callback does not work as expected. I have also tried using `.then(null, callback)`. How do I spy on the promise returned by `AuthenticationService.login` when given specific parameters? – rbutera Jul 13 '14 at 15:58
  • @BenjaminGruenbaum - Good point, there is some asynchronous work if the `(!credential && !password || credential === '' || password === '')` condition is not satisfied. I omitted it for the purposes of the SO question. – rbutera Jul 13 '14 at 16:00
  • To test promises I use Sinon (mocking library), in this test how mock a promise: http://stackoverflow.com/questions/20555234/how-does-one-stub-promise-with-sinon – Braulio Jul 13 '14 at 16:16

1 Answers1

3
it('promise should be rejected if any fields are empty', function(done) {
  AuthenticationService.login('','').catch(function(error){
    expect(error).toEqual('AuthenticationService.login - missing argument');
    done()
  });
  scope.$digest()
});

done - to explain you test framework when it's ready (in case of async operations)

scope.$digest() - to resolve all the promises

Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176
  • I'm now getting `TypeError: 'undefined' is not a function (evaluating '$rootScope.digest())` but this makes a lot more sense! – rbutera Jul 13 '14 at 16:05
  • I'm sorry, it should be "$" sign there before digest – Stepan Suvorov Jul 13 '14 at 19:09
  • it works without done()! thank you!!!! - but with done() I get an error `TypeError: 'undefined' is not a function (evaluating 'done()')` – rbutera Jul 13 '14 at 19:34
  • Note that the done() method was only added in version 2 of Jasmine. If you're using the Karma test-runner it still installs version 1.3 or something which is probably why done() isn't working for you. You can manually install version 2 of Jasmine and it will work fine with Karma. – Dominic Oct 06 '14 at 03:02