I have the following controller EditMeetingCtrl.js
(function() {
'use strict';
angular
.module('myApp')
.controller('EditMeetingCtrl', EditMeetingCtrl);
EditMeetingCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$translate',
'meetingService', 'companyService', 'notificationService', 'meeting'];
function EditMeetingCtrl($rootScope, $scope, $state, $http, $translate, meetingService, companyService, notificationService, meeting) {
$scope.meeting = meeting;
$scope.companyId = $state.params.companyId;
$scope.save = save;
function save() {
$scope.buttonDisable = true;
meetingService.saveMeeting($state.params.companyId, $state.params.meetingId, $scope.meeting)
.success(function(meetingId) {
//more code
});
}
}
})();
EditMeetingCtrlSpec.js test case
describe('in EditMeetingCtrl', function () {
var companyService , meetingService ;
meetingId = 123321 ;
companyId = 456654 ;
meetingObj = {} ;
var fakeHttpPromise = {
success: function() {}
};
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.inject(function (_$httpBackend_, _companyService_ , _meetingService_) {
$httpBackend = _$httpBackend_;
companyService = _companyService_;
meetingService = _meetingService_ ;
}));
describe('EditMeetingCtrl.save()', function () {
var $rootScope, scope, $controller , $q ;
beforeEach(inject(function ($rootScope, $controller , _meetingService_ ) {
scope = $rootScope.$new();
createController = function() {
return $controller('EditMeetingCtrl', {
$scope: scope,
meeting : {} ,
meetingService : _meetingService_
});
};
var controller = new createController();
}));
it("should save the meeting object", function() {
spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
scope.save();
expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
});
});
});
When try to run the below test casse EditMeetingCtrlSpec.js i got the following test failure
PhantomJS 1.9.8 (Windows 8) EditMeetingCtrl Spying --> EditMeetingCtrl.save() should save the meeting FAILED
Expected spy saveMeeting to have been called with [ 123321, 456654, Object({ }) ] but actual calls were [ undef
ined, undefined, Object({ }) ].
So the way understand my this problem , the service call for save()
method contains $state.params.companyId, $state.params.meetingId
parameters and it sends an undefined
values when the service call get invoked . therefore i need to mock the the $state.params
. Not sure how to do it .can anyone point me in the right direction ?
EDIT after Michael Radionov Answer
describe('EditMeetingCtrl.save()', function () {
var $rootScope, scope, $controller , $q , $state ;
beforeEach(inject(function ($rootScope, $controller , $state , _meetingService_ ) {
scope = $rootScope.$new();
createController = function() {
return $controller('EditMeetingCtrl', {
$scope: scope,
meeting : {} ,
meetingService : _meetingService_
});
};
var controller = new createController();
}));
it("should save the meeting", function() {
$state.params = { companyId: 123, meetingId: 567 };
spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
scope.save();
//expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
});
});
I have done the above, but i get the following error saying $state is not defined .
Firefox 38.0.0 (Windows 8.1) In EditMeetingCtrl EditMeetingCtrl.save() should save the meeting FAILED
TypeError: $state is undefined in C:/Users/sal/Documents/myApp/test/meeting/EditMe
etingCtrlSpec.js (line 80)
I assumed this happened because i did not do this -> $state : state
in the inject method, so i tried doing that too but got the same error . what am i missing here ?
The only caveat is you have to set an expectation that your mock get’s called, otherwise if it never gets executed the test will also never fail. 1) Set up the spy on the method for which you want to test the params. 2) Set up the expectation to compare a param to an expected value.
1) Set up the spy on the method for which you want to test the params. 2) Set up the expectation to compare a param to an expected value. 3) Call something that should call the method under test with the correct params. 4) Set up an expecatation that makes sure the method under test get’s actually called.
It’s about an occasional need to mock a promise and perhaps it’s callback params in Jasmine unit-tests and this is a simple example of how it can be done. This is an example of a function you might find in an AngularJS controller (written in TypeScript, but doesn’t matter, it would be almost identical in JS).
Jasmine is a simple, BDD -style JavaScript testing framework, but to benefit from the full power out of the framework, you need to know how to mock calls the Jasmine way. Jasmine uses spies to mock asynchronous and synchronous function calls.
You can mock the entire $state
provider and then specify exactly what values do you want to be in the params
property before calling save
:
describe('in EditMeetingCtrl', function () {
// ...
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.module(function ($provide) {
// mock the entire $state provider
$provide.provider('$state', function () {
return {
$get: function () {
return {
// by default it will be an empty object
params: {}
};
}
};
});
}));
// ....
describe('EditMeetingCtrl.save()', function () {
// inject mocked $state - one that you've provided above
var $rootScope, scope, $controller, $q, state;
// ---------------------------------------^^^
beforeEach(inject(function ($rootScope, $controller, $state, _meetingService) {
// ------------------------------------------------^^^
state = $state;
}));
// ...
it("should save the meeting object", function() {
// provide custom params which will be used in a call
state.params = { companyId: 123, meetingId: 567 };
spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
scope.save();
expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
});
});
// ...
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With