My question: In Karma, I am mocking an injected service while testing the actual service. The mocked service gets some data, and sends back a promise. I can't figure out what I am doing wrong.
I know there are a number of issues with the actual "Login" mechanism, but I am using it to illustrate this Karma question. I do not plan to use it as production code. (However, any suggestions for a better illustration of the problem are welcome!)
First, I wrote this in a generic .js file, and said "node testcode.js"
testcode.js:
function Login(name,password,callback){
setTimeout(function(){
var response;
var promise = getByUserName();
promise.then(successCb);
function successCb(userObj){
if ( userObj != null && userObj.password === password ) {
response = { success : true };
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
};
},200);
}
function getByUserName(){
return Promise.resolve(user);
}
var user = {
username : 'test',
id : 'testId',
password : 'test'
};
var test = undefined;
Login(user.username,user.password,testCb);
function testCb(response){
test = response;
console.log("Final: " + JSON.stringify(test));
}
This gives me my expected result:
Final: {"success":true}
Now, I try to repeat this in Karma...
TestService:
(function(){
"use strict";
angular.module('TestModule').service('TestService',TestService);
TestService.$inject = ['$http','$cookieStore','$rootScope','$timeout','RealService'];
})();
function TestService($http,$cookieStore,$rootScope,$timeout,RealService){
var service = {};
service.Login = Login;
/* more stuff */
return service;
function Login(username,password,callback){
$timeout(function () {
var response;
var promise = UserService.GetByUsername(username);
promise.then(successCb);
function successCb(user){
if (user !== null && user.password === password) {
response = { success: true };
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
};
}, 1000);
}
}
My Karma-Jasmine Test:
describe('TestModule',function(){
beforeEach(module('TestModule'));
describe('TestService',function(){
var service,$rootScope,
user = {
username : 'test',
id : 'testId',
password : 'test'
};
function MockService() {
return {
GetByUsername : function() {
return Promise.resolve(user);
}
};
};
beforeEach(function(){
module(function($provide){
$provide.service('RealService',MockService);
});
inject(['$rootScope','TestService',
function($rs,ts){
$rootScope = $rs;
service = ts;
}]);
});
/**
* ERROR: To the best of my knowledge, this should not pass
*/
it('should Login',function(){
expect(service).toBeDefined();
var answer = {"success":true};
service.Login(user.username,user.password,testCb);
//$rootScope.$apply(); <-- DID NOTHING -->
//$rootScope.$digest(); <-- DID NOTHING -->
function testCb(response){
console.log("I'm never called");
expect(response.success).toBe(false);
expect(true).toBe(false);
};
});
});
});
Why is the promise not being resolved? I have tried messing with $rootScope.$digest() based on similar questions I have read on SO, but nothing seems to get testCb to be called.