1

I'm trying to test my login controller, which should send users' login/password to the service and say if it exists in the service. Here is my code:

    describe('LoginController', function() {
    beforeEach(module('task6'));

    var $controller, LoginService;

    beforeEach(inject(function(_$controller_, _LoginService_) {
        $controller = _$controller_;
        LoginService = _LoginService_;
    }));

    describe('LoginController.submitLogin', function() {
        it('tests if such user exists', function() {
            var $scope = {};
            var controller = $controller('LoginController', 
                                         {$scope: $scope});
            controller.loginField = 'John';
            controller.password = 'Smith';
            LoginService.signIn(controller.loginField, 
                                controller.password)
            .then(function(logged) {
                expect(true).toBe(false);
            });
        });
    });
});

But it seems like tests in ".then" function never executed. It passes all the tests even with these conditions.

Vladimir Mironov
  • 655
  • 1
  • 7
  • 23
  • have you tried to read official documentation - https://docs.angularjs.org/api/ng/service/$q#testing ? Than you can try to read some article like e.g: http://brianmcd.com/2014/03/27/a-tip-for-angular-unit-tests-with-promises.html – Krzysztof Safjanowski Jan 18 '16 at 15:33
  • Yo, you can check this article (written by me) https://ath3nd.wordpress.com/2013/08/05/15/. Of course it is Restangular specific, but restangular is a service which uses promises so it should be close to what you want to achieve. Also, you can take a look at this: http://stackoverflow.com/questions/33367354/karma-jasmine-how-to-properly-spy-on-a-modal/33367678#33367678 – Nikola Yovchev Jan 18 '16 at 15:38

2 Answers2

1

This is because your are testing asynchronous code so you need to make the test asynchronous using done as follows ...

it('tests if such user exists', function(done) {
            .....
            LoginService.signIn(controller.loginField, 
                            controller.password)
            .then(function(logged) {
                expect(true).toBe(false);
                // done();
            }).catch(function(failure) {
                expect(true).toBe(true);
                done();
            })

        });
    });

done makes it wait for the promise to resolve / reject. if it doesn't resolve or reject within 2 seconds (default) then the test will fail.

danday74
  • 52,471
  • 49
  • 232
  • 283
  • Thank you! But somehow this doesn't work for me. I'm pretty sure that I'm doing the same thing you did, and I still get "Success" message on all tests... `LoginService.signIn(controller.loginField, controller.password) .then(function(logged) { expect(false).toBe(true); }) .catch(function(failure) { expect(true).toBe(false); done(); });` – Vladimir Mironov Jan 18 '16 at 17:27
  • ok your test code assume LoginService.signIn is returning a promise. Is that correct? maybe you can provide that code – danday74 Jan 18 '16 at 17:30
  • PS did you add ... it('tests if such user exists', function(done) ... notice the done here too - this is what makes the test async - the calls to done in the promise resolution merely denote the async test is complete – danday74 Jan 18 '16 at 17:31
  • I guess this could really be my problem. :) Here is the code ` function signIn(loginField, password) { return getUsers() .then(function(users) { for (var i = 0; i < users.length; i++) { if (users[i].login == loginField && users[i].password == password) { $rootScope.logged = true; $rootScope.user = users[i].login; $location.path('/courses'); return true; } } return false; }) .catch(function () { console.log("Error: Users array wasn't retrieved from the server"); return false; }); }` – Vladimir Mironov Jan 18 '16 at 17:38
  • ok i will add another answer to show you how to return a promise from signIn function – danday74 Jan 18 '16 at 17:51
  • Thank you! You were totally right, I have forgotten to add `function(done)`. :) Now tests are always failed because of timeouts, but this is a totally different problem, I guess. So thank you very much for your help! :) – Vladimir Mironov Jan 18 '16 at 17:52
1
function signIn(username, password) {
   /// THIS RETURNS A PROMISE BECAUSE $http returns a promise. Thus you can call THEN method on the return value because all promises have a THEN method.
   return $http.post('myserver', {username:username, password:password});
}



// Another approach using $q

function signIn(username, password) {
   var defer = $q.defer();
   if (username==="fred" && password==="mypass") {
        defer.resolve("nice one");
   } else {
        defer.reject("oh dear");
   }
   return defer.promise;
}

Here both approaches return a promise. so now, when I call the function I can call THEN on its return value (because the return value is a promise) ...

signIn("fred", "badpass").then(function(response) {
    console.log(response);
}).catch(function(failure) {
    console.log(failure);
});
danday74
  • 52,471
  • 49
  • 232
  • 283