function containing a Jasmine test scenario for Restangular

How can I create jasmine tests for a Rectangular scenario like the one shown 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 have written test cases as shown below, but I am encountering an exception stating

spyOn could not find an object to spy upon for all()

test case

WORKING DEMO - contains the full logic and 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();

        }));
    });
});

Answer №1

You are facing multiple issues:

First, in order to use toHavebeenCalled to answer your question, you need to create a spy first.

One way to do this is by setting setMyEmployees at the scope level and then adding a spy on the scope

spyOn($scope);

However, there is a test that makes an asynchronous request, causing your test case to fail because it will reach the end before the asynchronous request is successful.

In Jasmine 2, you can use done() for asynchronous tests:

it('should add new employees when addEmployees() is called', function(done) 
{
    //call when asynchronous operation is finished
    done();
}

But with the way your function is created, you can't use done. You will need to have a callback block in your method or a promise

Callback :

$scope.addEmployees = function(employeesCopy, success, failure)
{
    //code
    Restangular.all('user/getEmployees').post(employeeList).then(function(employees)
    {
        if (!_.isEmpty(employees[employeeList.employeeId]))
        {
           // code
        }
        else
        {
            // code
        }
        success();
        $scope.flag = false;
    }, function(error)
    {
        failure();
        $scope.flag = false;
    });
};

Take note of the toHaveBeenCall syntax

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 a promise syntax:

$scope.addEmployees = function(employeesCopy, defer)
{
    //code
    Restangular.all('user/getEmployees').post(employeeList).then(function(employees)
    {
        if (!_.isEmpty(employees[employeeList.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 final issue you may encounter is mocking the network call if you want your test to be truly unitary (otherwise, you're also testing the backend response, which might not be desired). If you wish to mock the call, consider using $httpBackend. This blog post provides more information: (not mine)

EDIT, add dependency to test, before your it(), use a beforeEach:

var myService, Restangular;
    beforeEach(function() {
        inject(function($injector) {
            myService = $injector.get('MyService');//example service
            Restangular = $injector.get("Restangular");
        });
    });

EDIT 2:

Apologies for not explaining it clearly, 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
        });
    }));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Acquiring images from an external source and storing them in either the $lib directory or the static folder during the

Currently, I have a Sveltekit project set up with adapter-static. The content for my pages is being pulled from Directus, and my images are hosted in S3, connected to Directus for easy access. I am also managing audio samples in a similar manner. During b ...

Adding a unique header to an Ajax CORS request can be achieved by following a few

Searching for a way to include a custom header for Ajax CORS request? Look no further! My server is PHP Lumen and the proxy server is Nginx. The file bootstrap/app.php holds my project configuration details https://i.sstatic.net/zxM7G.png I've come ...

Unable to trigger button retrieved through ajax request

I am facing a minor issue with my php page. It returns a button using ajax, as you can see below: HTML snippet: <a href="#" class="unit_register_button"> Register </a> jQuery code: $('a.unit_register_button').click(function(e) ...

Experience the Power of Vue.js in Your Shopify Store

I have encountered an issue while attempting to integrate 3 custom modals into Shopify. Upon implementing them, I received the following error in the console (not originating from my Vue files, but rather from the Shopify template): [Vue warn]: Error comp ...

Obtaining undefined values for req and resolvedUrl in GetServerSideProps function

In my project, I am currently using next.js version ""next": "^12.1.4"" and node version ""@types/node": "^14.14.6". I have created a function called getServerSideProps with parameters req and resolvedUrl. When the ...

Monitoring all changes with AngularJS in the ng-init function

When working with an AngularJS controller, I set some variables on the server side using ng-init. /* Setting variables in server side View */ <div ng-controller="myController" ng-init="myFoo=@myFoo;myBar=@myBar">...</div> /* Controller logic ...

Error encountered when attempting to call a JavaScript function by clicking on a link within a dropdown menu due to an unexpected end of

Here is the code snippet from my HTML file: <html> <head> <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css"> <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/boots ...

Having difficulty retrieving the JSON response using AngularJS

Looking to retrieve the build values from apache.org using their API link: I attempted to use angularjs $http.jsonp to fetch the data, but encountered difficulties. In the Chrome console, the JSON API loads successfully in the network tab, but the actual ...

Leveraging JavaScript Functions in HTML

I am having an issue with a JavaScript file containing two similar functions that are executed through an HTML form. While the first function runs smoothly, the second function does not display correctly. It seems like I might be calling or executing the ...

What could be the reason why modifications made to $scope in a directive's link function do not appear on the user interface?

The AngularJS directives' link function causes changes to isolate scope data that are not reflected in the UI. Take a look at this example: var myApp = angular.module('myApp', []); myApp.directive('myDirective', function () { ...

Unable to retrieve custom date picker value with React Antd

I have implemented a custom datepicker for entering dates in the 'MMDD' or 'MMDDYY' format. The date value is stored in state and used in the datepicker component as a controlled component. However, upon form submission, the datepicker ...

AngularJS is encountering a problem with its filter functionality, particularly when trying to filter using a combination of uppercase and lowercase letters

Dealing with an issue in angularjs 1.6 related to filtering I attempted to use toLowerCase() on an array of items but it didn't work. Can anyone assist me with how to resolve this problem in the filter. Below is the code snippet, <input type="te ...

What purpose does @ViewChild serve if we are unable to modify or interact with its properties from the Parent Component?

I have two main components - home and about. Within both of these, I am including a third component called hearts. Currently, I am manipulating the value of the 'age' property in the hearts component (initially set to '23') using @ViewC ...

Eliminate any unnecessary line breaks within the text box

Is there a way to identify line breaks in a text area using Java script? If two consecutive blank lines are found, remove one of them. If there is only one line present, delete it as well. I'm currently only able to delete single lines. Can anyone he ...

What could be causing the issue when the selected option is being changed and the condition does not work

Whenever the selection in a select element is changed, the corresponding text should also change. Check out this Fiddle here. (function($) { 'use strict'; function updateResultText() { var s1_is_1 = $("#s1").value === '1', ...

Looking to minify a JavaScript file? Consider changing the overly long variable name "veryLoooooooongVariable" to something shorter,

When working on improving readability, I tend to use very long variable names which can increase the size of my JS files. I'm wondering if there are any tools or libraries available that can automatically change these long names to shorter ones? I am ...

Using Javascript to handle form submission and enforce required input fields

Has anyone encountered an issue when trying to submit form data using a div, HTML5, and JavaScript? I noticed that if I use a submit button with the required attribute in the inputs, the validation works but the button doesn't actually submit the info ...

How to efficiently close all active Bootstrap modals in an AngularJS application?

I'm dealing with a situation where I've created a modal within another modal. My goal is to use the second modal as a confirmation box to close the first one. However, I'm having trouble getting both modals to close when clicking 'ok&ap ...

How to stop URL switch and page reload in Bootstrap 4 navigation bars

Currently, I am utilizing Bootstrap 4 and AngularJS for the development of an application. Within this, I am incorporating a modal that includes navigation tabs from Bootstrap 4. However, I am encountering an issue where the navigation tabs use hrefs that ...

Where can I find the HTML code I just inserted?

Why isn't the newly added jQuery code visible when inspecting the view-source after the jQuery trigger? The script below adds a simple alert-info paragraph (refer to the image) when the password is incorrect. See how the page appears after the code ...