Reputation: 19294
I'm learning unit-testing in angularjs and i'm trying to test my authentication controller.
Currently the test is failing with Expected Function to equal '/dashboard'
. The test does not seem to be getting into User.login
from what I can tell.
Controller:
angular.module('foo').controller('LoginCtrl',function($scope, $rootScope, $http, $window, $location, User){
$scope.submit = function () {
User.login($scope.user,
function (user) { // Success
$window.sessionStorage.token = user.id;
$scope.message = 'Welcome';
// Redirect to dashboard
$location.path('/dashboard');
},
function (err) {
console.log(err);
// handle login errors
$scope.message = 'Error: Invalid user or password';
}
);
};
});
Test:
describe('LoginCtrl', function() {
beforeEach(module('foo'));
var scope, ctrl, location, window, user;
beforeEach(inject(function($rootScope, $controller, $location, $window, User) {
scope = $rootScope.$new();
location = $location;
window = $window;
user = User;
ctrl = $controller('LoginCtrl', {$scope: scope, User: user});
}));
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
scope.submit();
console.log('message = '+scope.message);
console.log('after path = '+location.path());
console.log(window.sessionStorage.getItem('token'));
expect(location.path).toEqual('/dashboard');
});
});
** EDIT **
User.login code:
module.factory(
"User",
['LoopBackResource', 'LoopBackAuth', '$injector', function(Resource, LoopBackAuth, $injector) {
var R = Resource(
urlBase + "/users/:id",
{ 'id': '@id' },
{
"login": {
url: urlBase + "/users/login",
method: "POST",
interceptor: {
response: function(response) {
var accessToken = response.data;
LoopBackAuth.currentUserId = accessToken.userId;
LoopBackAuth.accessTokenId = accessToken.id;
LoopBackAuth.rememberMe = response.config.params.rememberMe !== false;
LoopBackAuth.save();
return response.resource;
}
}
}
});
Upvotes: 1
Views: 497
Reputation: 48972
Your User.login
function must be calling the callback method asynchronously, so when you call scope.submit();
, your callback function is not called yet => the test fails.
To test this logic, you have to mock the User.login
function:
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
//user here is user = User; in your beforeEach. I avoid pasting too much code.
//Jasmine 1.3: andCallFake
//Jasmine 2.0: and.callFake
spyOn(user, "login").andCallFake(function(userData,successCallback){
successCallback(userData); //simulate the success case.
}); //mock your User.login
scope.submit();
console.log('message = '+scope.message);
console.log('after path = '+location.path());
console.log(window.sessionStorage.getItem('token'));
expect(location.path()).toEqual('/dashboard'); //fix the problem with location.path
});
Explanation:
spyOn(user, "login").andCallFake
replaces the actual function with our fake function.
In this test case, you're testing should redirect upon successful login
, so the precondition is the login must be successful, by mocking the login function, we can ensure this precondition is always true in the test.
You could do this similarly to test a case like: set error message when login failed
, in order to test this, you need to ensure the precondition login failed
is always true in the test:
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
//user here is user = User; in your beforeEach. I avoid pasting too much code.
//Jasmine 1.3: andCallFake
//Jasmine 2.0: and.callFake
spyOn(user, "login").andCallFake(function(userData,successCallback,errorCallback){
errorCallback(userData); //simulate the error case.
}); //mock your User.login
scope.submit();
expect(scope.message).toEqual('Error: Invalid user or password'); //verify that the message was set correctly.
});
Upvotes: 2
Reputation: 35900
Expected Function to equal '/dashboard'
The test runner is telling you it expected a string '/dashboard'
, but instead got a reference to a function. That's because location.path
is a reference to a function. Try this instead:
expect(location.path()).toEqual('/dashboard');
Upvotes: 2