Reputation: 10714
I'm trying to unit test a controller with a service injected into it. No matter what I seem to try, I get an error. Any assistance to help me get this going would be much appreciated. I'm using Angular/Karma/Jasmine to get run my tests.
There seem to be a lot of posts with similar stories but this feels like it may not be a duplicate - apologies if it is.
My controller looks like this:
(function() {
angular
.module('blah')
.controller('AdminController', AdminController);
/* @ngInject */
function AdminController($scope, toastr, adminService) {
activate();
/**
* Controller initialisation.
*/
function activate() {
getAllUsers();
}
/**
* Gets all users.
*/
function getAllUsers() {
adminService.getAllUsers()
.then(function(response) {
$scope.users = response.data;
})
.catch(function(error) {
toastr.error('Unable to load users', 'Error');
console.log(error);
});
}
}
})();
And my service looks like this:
(function() {
angular
.module('blah')
.factory('adminService', adminService);
/* @ngInject */
function adminService($http, environmentConfig) {
var service = {
getAllUsers: getAllUsers
};
return service;
/**
* Gets all user objects.
*/
function getAllUsers() {
return $http.get(environmentConfig.apiBaseUrl + '/user');
}
}
})();
and my unit tests look like this:
describe('AdminController', function() {
var ctrl,
adminService,
$scope;
var listOfTestUsers = [
{ name: 'Dave', id: 1 },
{ name: 'Bob', id: 2 },
{ name: 'Bill', id:3 }
];
beforeEach(function() {
module('blah');
});
beforeEach(inject(function($rootScope, $controller) {
adminService = {
getAllUsers: function() {}
};
spyOn(adminService, 'getAllUsers').and.returnValue(listOfTestUsers);
$scope = $rootScope.$new();
ctrl = $controller('AdminController', {
$scope: $scope,
adminService: adminService
});
}));
describe('The getAllUsers function should exist', function() {
it('should work', function() {
expect(ctrl).toBeDefined();
});
});
});
I get this error when running my Jasmine tests with Karma:
TypeError: adminService.getAllUsers(...).then is not a function
Upvotes: 1
Views: 1263
Reputation: 39482
Here are a few things that I found wrong with the code.
.catch
was used earlier. .then
is called with two callbacks, a success callback and an error callback. So that's what I've done in your call to adminService.getAllUsers
.
For the TypeError: adminService.getAllUsers(...).then is not a function
that you were getting. You didn't mock getAllUsers properly. I've done that in the testCases file. It returns a function named then
which was not available earlier.
Controller
(function() {
angular
.module('blah', [])
.controller('AdminController', AdminController);
/* @ngInject */
function AdminController($scope, toastr, adminService) {
$scope.greeting = "Hello World!";
/**
* Gets all users.
*/
$scope.getAllUsers = function() {
adminService.getAllUsers()
.then(function(response) {
$scope.users = response.data;
}, function(error) {
toastr.error('Unable to load users', 'Error');
console.log(error);
});
}
activate();
/**
* Controller initialisation.
*/
function activate() {
$scope.getAllUsers();
}
}
})();
environmentConfig Constant. Replace this with yours.
(function() {
angular.module('blah').constant('environmentConfig', {
apiBaseUrl: 'https://www.something.com'
})
})();
toastr Service. Replace this with yours
(function() {
angular
.module('blah')
.factory('toastr', toastr);
/* @ngInject */
function toastr() {
var service = {
error: error
};
return service;
/**
* Gets all user objects.
*/
function error(a, b) {
console.log("Here's the error : ", a);
}
}
})();
adminService
(function() {
angular
.module('blah')
.factory('adminService', adminService);
/* @ngInject */
function adminService($http, environmentConfig) {
/**
* Gets all user objects.
*/
function getAllUsers() {
return $http.get(environmentConfig.apiBaseUrl + '/user');
}
var service = {
getAllUsers: getAllUsers
};
return service;
}
})();
Test Cases
describe('controller: AdminController', function() {
var scope, $scope, toastr, adminService, AdminController, flag, $q;
flag = 'success';
var listOfTestUsers = [{
name: 'Dave',
id: 1
}, {
name: 'Bob',
id: 2
}, {
name: 'Bill',
id: 3
}];
beforeEach(module('blah'));
beforeEach(inject(function($controller, $rootScope, _toastr_, _adminService_, _$q_) {
scope = $rootScope.$new();
toastr = _toastr_;
adminService = _adminService_;
$q = _$q_;
spyOn(adminService, 'getAllUsers').and.callFake(function() {
return flag === 'success' ? $q.when(listOfTestUsers) : $q.reject("Error");
});
AdminController = $controller('AdminController', {
$scope: scope,
toastr: _toastr_,
adminService: _adminService_
});
}));
describe('The getAllUsers function should exist', function() {
it('should work', function() {
expect(AdminController).toBeDefined();
});
});
});
Hope this helps.
Upvotes: 3
Reputation: 21
Your actual error is the fact that your mock service does not have the function 'getAllUsers' here is a paste bin with the adjustments http://pastebin.com/LwG0CzUW
If you prefer you could adjust your test to call the actual service as the following pastebin.
Upvotes: 0
Reputation: 1060
Your controller code is causing the error. You should be callling $scope.getAllUsers(); in your activate function, not "getAllUsers()".
Upvotes: 0