In the below SampleController, how do I unit test that postAttributes function calls sampleService.updateMethod. I'm having trouble since the updateMethod returns promise.
angular.module('sampleModule')
.controller('SampleController', SampleController);
SampleController.$inject =['sampleService'];
function SampleController(sampleService){
this.postAttributes = function() {
sampleService.updateMethod(number,attributes)
.then(function(response){
//do something on successful update
},function(response){
//do something on unsuccessful update
});
};
}
Here is the factory service that I have:
angular.module('sampleModule')
.factory('sampleService', sampleService);
sampleService.$inject = ['$http'];
function sampleService($http) {
return {
getMethod: function(acctNumber){
return $http({
method: 'GET',
url: //api endpoint
});
},
updateMethod: function(number, attributes){
return $http({
method: 'PUT',
url: //api endpoint,
data: //payload
});
}
};
}
I would like to mock the factory service in the controller spec rather than injecting the actual service directly into $controller, since most of unit testing guidelines specify to test a unit under isolation.
Sample controller spec:
describe('SampleController Test', function(){
var $controller;
var service;
beforeEach(angular.mock.module('sampleModule'));
beforeEach(angular.mock.inject(function(_$controller_){
$controller = _$controller_;
}));
it('Testing $scope variable', function(){
var sampleController = $controller('SampleController', {
sampleService: service, //mocked factory service
});
sampleController.postAttributes(); //calling the function first
//here I would like to make an assertion to check if
//sampleService.updateMethod has been called with certain parameters
//how do I do that??
});
});
Googled around and found a solution to mock the factory service and followed promise creation approach like @TehBeardedOne and made it to return it from the mocked service.
describe('SampleController', function(){
var mockService, controller, deferred, $rootScope;
beforeEach(function(){
angular.mock.module('sampleModule');
angular.mock.module(function($provide){
$provide.factory('sampleService', function($q){
function updateMethod(acct, attr){
deferred = $q.defer();
return deferred.promise;
}
return{updateMethod: updateMethod};
});
});
angular.mock.inject(function($controller, sampleService, _$rootScope_){
$rootScope = _$rootScope_;
mockService = sampleService;
spyOn(mockService, 'updateMethod').and.callThrough();
controller =$controller('SampleController', {
sampleService: mockService,
})
});
});
it('postAttributes function should call updateMethod', function(){
controller.postAttributes();
expect(mockService.updateMethod).toHaveBeenCalled();
expect(mockService.updateMethod).toHaveBeenCalledWith(controller.accountNumber, controller.attributes);
});
it('postAttributes success block', function(){
controller.postAttributes();
var res = {
data: '2323'
}
deferred.resolve(res);
$rootScope.$digest();
expect(//something in success block).toBe(something);
});
it('postAttributes failure block', function(){
controller.postAttributes();
var res = {
data: '9898'
}
deferred.reject(res);
$rootScope.$digest();
expect(controller.lame).toBe('dont type shit');
});
});
I've mocked the sampleService with $provider service and made updateMethod to return a promise using $q. Later on you can resolve or reject the promise and test the success and failure blocks in individual it blocks.