Jasmine test case for Restangular within a function
How to write jasmine test for Rectangular for scenario as below
script
$scope.allEmployees = [{
visible: true,
empId: "EMP148"
}];
$scope.employeeDocuments = { "EMP148": [{
"empId": "EMP148",
"department": "Sales",
"firstName": "Manu",
"lastName": "Mathew",
"place": "Kolkata"
}]
};
var employeesCopy = angular.copy($scope.allEmployees);
$scope.allEmployees.push({visible: true, empId: "EMP489"});
$scope.addEmployees = function (employeesCopy) {
var newEmployee = {visible: true, empId: "EMP489"};
var emplyeeList = {
employees: $scope.allEmployees,
newEmployee: newEmployee
};
Restangular.all('emp/getEmployees').post(emplyeeList).then(function (employees) {
if (!_.isEmpty(employees[emplyeeList.newEmployee.empId])) {
if ($scope.employeeDocuments.hasOwnProperty(emplyeeList.newEmployee.empId)) {
delete $scope.employeeDocuments[emplyeeList.newEmployee.empId];
}
$scope.employeeDocuments[emplyeeList.newEmployee.empId] = employees[emplyeeList.newEmployee.empId];
setMyEmployees(true);
$scope.flag = true;
console.log("success");
} else {
$scope.employeeDocuments = employeesCopy;
console.log("no documents");
}
$scope.flag = false;
}, function (error) {
console.log("failed");
$scope.flag = false;
});
};
$scope.addEmployees(employeesCopy);
setMyEmployees = function (flag)
{
// other implementation
};
I wrote test cases as shown below, but I am getting an exception like spyOn could not find an object to spy upon for all()
test case
WORKING DEMO - contains complete logic as well as test cases
describe('Testing Controllers', function() {
describe('Testing EmployeeController Controller', function() {
var EmployeeController, $scope, $httpBackend, Restangular;
beforeEach(function() {
module('emp');
});
beforeEach(inject(function($controller, $rootScope, $filter, $injector, Restangular, $httpBackend) {
$scope = $rootScope.$new();
$httpBackend = $httpBackend;
Restangular = $injector.get("Restangular");
EmployeeController = $controller('EmployeeController ', {
$rootScope: $rootScope,
$scope: $scope,
$filter: $filter
});
}));
it('should add new employees when addEmployees() is called', inject(function($httpBackend)
{
$scope.allEmployees = [{
visible: true,
empId: "EMP148"
}];
$scope.employeeDocuments = { "EMP148": [{
"empId": "EMP148",
"department": "Sales",
"firstName": "Manu",
"lastName": "Mathew",
"place": "Kolkata"
}]
};
var employeesCopy = angular.copy($scope.allEmployees);
spyOn(Restangular, 'all').andCallThrough();
var newEmployee = {visible: true, empId: "EMP489"};
var emplyeeList = {
employees: $scope.allEmployees,
newEmployee: newEmployee
};
var mockToReturn = {
"EMP489": [{
"empId": "EMP489",
"department": "Sales",
"firstName": "Ram",
"lastName": "Mohan",
"place": "Delhi"
}]
};
$scope.addEmployees(employeesCopy);
$httpBackend.expectPOST('emp/getEmployees',emplyeeList).respond(mockToReturn);
expect(Restangular.all).toHaveBeenCalledWith('emp/getEmployees');
expect(setMyEmployees(true)).toHaveBeenCalled();
}));
});
});
source to share
You have a problem with multiple values:
First, to answer your question, in order to use toHavebeenCalled, you need to create a spy first.
What I would do is put setMyEmployees at the scope level and then add the spy to the scope
spyOn($scope);
But you have a test that makes an asynchronous request, so your test case will fail because it will reach the end before the asynchronous request is successful.
With jasmine 2, you can use done () for an asynchronous test:
it('should add new employees when addEmployees() is called', function(done)
{
//call when asyncronous operation is finish
done();
}
But the way you created your function, you cannot use it. You will need to have a callback block in your method or promise
Callback:
$scope.addEmployees = function(employeesCopy, success, failure)
{
//code
Restangular.all('user/getEmployees').post(emplyeeList).then(function(employees)
{
if (!_.isEmpty(employees[emplyeeList.employeeId]))
{
// code
}
else
{
// code
}
success();
$scope.flag = false;
}, function(error)
{
failure();
$scope.flag = false;
});
};
Pay attention to the syntax toHaveBeenCall
it('should add new employees when addEmployees() is called', function(done)
{
var employeesCopy = {
firstName: "Manu",
lastName: "Sam"
};
spyOn($scope);
$scope.addEmployees(employeesCopy, function(){
done();
});
expect($scope.setMyEmployees).toHaveBeenCalledWith(true);
});
I would prefer the promise syntax:
$scope.addEmployees = function(employeesCopy, defer)
{
//code
Restangular.all('user/getEmployees').post(emplyeeList).then(function(employees)
{
if (!_.isEmpty(employees[emplyeeList.employeeId]))
{
// code
}
else
{
// code
}
defer.resolve();
$scope.flag = false;
}, function(error)
{
defer.reject();
$scope.flag = false;
});
};
it('should add new employees when addEmployees() is called', function(done)
{
var employeesCopy = {
firstName: "Manu",
lastName: "Sam"
};
spyOn($scope);
var defer = $q.defer;
defer.promise.then(function(){
console.log("success");
done();
}, function (){
done();
console.log("error");
});
$scope.addEmployees(employeesCopy, defer);
expect($scope.setMyEmployees).toHaveBeenCalledWith(true);
});
The last problem is to mock the net call if you want your test to be truly unitary (otherwise you also check the backend response, which might be what you want) If you want to mock the call, you should look at $ httpBackend, this blog post seems to have more info: https://ath3nd.wordpress.com/2013/08/05/15/ (not mine)
EDIT add dependency to test before you () it, use beforeEach:
var myService, Restangular;
beforeEach(function() {
inject(function($injector) {
myService = $injector.get('MyService');//exemple service
Restangular = $injector.get("Restangular");
});
});
EDIT 2:
Ok I won't explain it correctly, try:
beforeEach(inject(function($controller, $rootScope, $filter, $injector, _Restangular_, _$httpBackend_) {
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
Restangular = _Restangular_;
EmployeeController = $controller('EmployeeController ', {
$rootScope: $rootScope,
$scope: $scope,
$filter: $filter
});
}));
source to share