Spy on a service method call using jasmine Spies
46,770
describe('ViewMeetingCtrl', function () {
var scope, meetingService;
beforeEach(angular.mock.module('MyApp'));
beforeEach(inject(function ($rootScope, $controller, _meetingService_) {
scope = $rootScope.$new();
meetingService = _meetingService_;
$controller('ViewMeetingCtrl', {
$scope: scope,
meeting : {}
});
}));
it('should send cancel notices whan cancelMeeting is called', function() {
var fakeHttpPromise = {
success: function() {}
};
spyOn(meetingService, 'sendCancelNotices').andReturn(fakeHttpPromise);
scope.cancelMeeting('foo', 'bar');
expect(meetingService.sendCancelNotices).toHaveBeenCalledWith('bar', 'foo');
});
});
I would encourage you to stop relying of HTTP promises being returned from services. Instead, just consider the service returns a promise. Those are easier to mock, and won't force you to rewrite your controller code when you don't return HTTP promises anymore.
In your controller:
function cancelMeeting(meetingId, companyId) {
meetingService.sendCancelNotices(companyId, meetingId)
.then(function () {
$state.go('company.view');
});
}
In your test:
var fakePromise = $q.when();
spyOn(meetingService, 'sendCancelNotices')and.returnValue(fakePromise);
scope.cancelMeeting('foo', 'bar');
expect(meetingService.sendCancelNotices).toHaveBeenCalledWith('bar', 'foo');
Author by
Malik
Updated on July 09, 2022Comments
-
Malik almost 2 years
I have the following controller ViewMeetingCtrl.js
(function () { 'use strict'; angular.module('MyApp').controller('ViewMeetingCtrl', ViewMeetingCtrl); ViewMeetingCtrl.$inject = ['$scope', '$state', '$http', '$translate', 'notificationService', 'meetingService', '$modal', 'meeting', 'attachmentService']; function ViewMeetingCtrl($scope, $state, $http, $translate, notificationService, meetingService, $modal, meeting, attachmentService) { $scope.meeting = meeting; $scope.cancelMeeting = cancelMeeting; function cancelMeeting(meetingId, companyId) { meetingService.sendCancelNotices(companyId, meetingId) .success(function () { $state.go('company.view'); }); } } })();
I was able to succussfully invoke the spyOn for cancelMeeting() but not with the calling of sendCancelNotices method. What i want to do is , i want to test that whenever cancelMeeting() gets called , it calls sendCancelNotices() method . I know that i should go with createSpy method to do this . But i am not sure how to do it .
Below is the test case ViewMeetingCtrlSpec.js
describe('ViewMeetingCtrl CreateSpy --> Spying --> cancelMeeting', function () { var $rootScope, scope, $controller , $q ; var sendCancelNoticesSpy = jasmine.createSpy('sendCancelNoticesSpy'); beforeEach(angular.mock.module('MyApp')); beforeEach(inject(function ($rootScope, $controller ) { scope = $rootScope.$new(); createController = function() { return $controller('ViewMeetingCtrl', { $scope: scope, meeting : {} }); }; var controller = new createController(); })); it("tracks that the cancelMeeting spy was called", function() { //some assertion }); });
-
Malik almost 9 yearsthank you for your answer . that exactly what i wanted . however there was a small change needed to be done (and.returnValue()) since i am using jasmine 2.0
-
Shailesh Vaishampayan over 8 yearsIn above code we are calling spyOn (and we can call createSpyObj to get entire mocked object)on real service instance of MeetingService.Correct?In our code we are just creating a spy object on a String object where value of the String is same as name of the service. We write something : beforeEach(function(){ $provide.factory("meetingService",function(){ meetingServiceMock = jasmine.createSpyObj("meetingService",['sendCancelNotices']); return meetingServiceMock;}); and then use this meetingServiceMock everywhere in "it" blocks. Even if it works correctly..do not think it makes sense does it?
-
JB Nizet over 8 yearsIt does make sense, but it's more work, and you always have the risk of creating a mock service that doesn't have the same methods as the actual service.
-
Shailesh Vaishampayan over 8 yearsOK.it makes sense because you can still record and verify the spy calls. And it's more work because I have to explicitly retrieve it using one $provide per service I have to mock. Correct?
-
Shailesh Vaishampayan over 8 yearsAnd why is it a risk ? If I am explicitly listing which methods spies I want in the mocked object which I have to do anyway while creating a mock even if its the actual instance? Can you please explain. One risk is that I cannot use call through on the spy as the instance on which I am creating spies and mock is not actual service instance but a string instance. Am I correct in this assumption?
-
JB Nizet over 8 yearsIt's a risk because your tests can pass even though the component they test uses methods that only exist in the mock, and not in the actual service.
-
Shailesh Vaishampayan over 8 yearsYes. but I am including methods while creating mock that exist only in the service. Is my assumption in last comment correct about callThrough?
-
Shailesh Vaishampayan over 8 yearsCan you also please help me with following question :stackoverflow.com/questions/33938552/…
-
Tony Brasunas over 3 yearsNote that if you're reading this in 2020 or later, the jasmine functions have changed. Should be
spyOn(meeetingService, 'sendCancelNotices').and.returnValue(fakeHttpPromise)