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();

        }));
    });
});

      

+3


source to share


1 answer


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
        });
    }));

      

+6


source







All Articles