Reputation: 3616
I'm attempting to test my Angular controllers and need to mock several services in order to do so. I'll focus on one service in this question as the rest function similarly. I use dependency injection to get ahold of playersService
and use it like so in my controller:
angular.module('gameApp')
.controller('PlayerInfoController', PlayerInfoController);
PlayerInfoController.$inject = ['$scope', '$routeParams', 'playersService'];
function PlayerInfoController($scope, $routeParams, playersService) {
var vm = this;
var playerId = $routeParams.playerId;
playersService.getDetails({
playerId: playerId
}).$promise.then(function(details) {
vm.details = details;
});
}
The relevant service looks like this:
angular.module('gameApp')
.factory('playersService', ['$resource',
function($resource) {
var base = '/api/players/:playererId/';
return $resource(base, {}, {
getDetails: {method: 'GET', url: base + 'details'}
});
}]);
Below is my current unit test setup which fails with the following error: TypeError: 'undefined' is not an object (evaluating 'playersService.getDetails({playerId: playerId}).$promise.then')
describe('PlayerInfoController', function() {
var scope;
var routeParams;
var playersService;
beforeEach(function() {
var mockPlayersService = {};
module('gameApp', function($provide) {
$provide.value('playersService', mockPlayersService);
});
inject(function($q) {
mockPlayersService.details = {
'firstName': 'John',
'lastName': 'Doe',
'country': 'US'
};
mockPlayersService.getDetails = function(playerId) {
var defer = $q.defer();
defer.resolve(this.details);
return defer.promise;
};
});
});
beforeEach(inject(function($controller, $rootScope, _$routeParams_, _playersService_) {
scope = $rootScope.$new();
routeParams = _$routeParams_;
playersService = _playersService_;
$controller('PlayerInfoController', {$scope: scope, $routeParams: routeParams, playersService: playersService});
scope.$digest();
}));
it('should say 2 === 2', function() {
expect(2).toEqual(2);
});
});
Upvotes: 1
Views: 4719
Reputation: 1931
playersService.getDetails normally returns a relatively empty object with the property $promise, once the call finishes this object is populated with the result.
Your mockPlayersService.getDetails needs to return a similar object, so something like this should do:
mockPlayersService.getDetails = function(playerId) {
var defer = $q.defer();
defer.resolve(this.details);
return angular.extend({$promise: defer.promise}, this.details);
};
And as a note, according to the angular docs you typically use your service like this (the second parameter can be a function to call on success instead of using $promise).
playersService.getDetails({
playerId: playerId
}, function(details) {
vm.details = details;
});
That would also require you to modify your mock service.
Upvotes: 2