Testing an AngularJS factory in Jasmine using two dependencies: $http and another factory that returns a promise

I'm currently using the Ionic framework to develop custom applications. Right now, I'm working on writing Unit tests for the factory datastoreServices, which has dependencies on DomainService and $http. I'm struggling with implementing Jasmine Unit tests and could use some guidance.

Here are my factory functions:

app.factory("datastoreServices", ["$http", function($http) {
    return {
        getData: function(data, DomainService) {
            return $http.post(DomainService.host + 'factor', data);
        }
    };
}]);

app.factory('DomainService', function() { //here
    if (ionic.Platform.isAndroid()) {
        return {
            host: 'http://10.0.2.2:7001/'
        }
    }
    return {
        host: 'http://localhost:7001/'
    }
})

Below is my unit test skeleton. With two dependencies, I'm unsure how to proceed. This is what I have so far in my unit test file:

describe(
        'datastoreServices',
        function() {
            beforeEach(module('Myapp'));
            describe('getData'),
                function() {
                    it("Should return correct values", inject(function(datastoreServices, DomainService, $httpBackend) {
                            expect(datastoreServices.getData(httpBackend.. /***something here!**/ )
                                .toEqual("2.2");
                            }))
                    }

I have limited knowledge on mocking and testing. Can someone assist me in testing the factory datastoreServices? The following aspects need to be tested:

  • Is the Http post making the correct calls?
  • Is the function returning the correct promise?

Here is a similar app scenario in plnkr.

I hope I'm not asking too much. Thank you in advance.

Answer №1

The fundamental principles to keep in mind are:

  • When testing, $http is mocked to avoid actual server calls during test execution.
  • It is necessary to use $httpBackend to validate http calls and mimic server responses. More information can be found here.
  • You have the flexibility to inject or mock any dependencies required for your test scenarios.

Let's examine a sample based on your original code:

    describe('datastoreServices', function() {

    beforeEach(module('MyApp'));

    // Set up the $httpBackend mock and the service to be tested, also create a mock for DomainService
    var $httpBackend, datastoreServices, DomainService;
    beforeEach(inject(function(_$httpBackend_, _datastoreServices_) {
        $httpBackend = _$httpBackend_;
        datastoreServices = _datastoreServices_;
        DomainService = function() {
            return {
                host: 'http://localhost:7001/'
            };
        };
    }));

    // After each test, ensure that all expected http calls were made and only those
    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });


    it('triggers http backend to fetch data', function() {
        var data = {foo: 'bar'};

        // Define the $http expectation and specify a mock server response for the request
        // Refer to https://docs.angularjs.org/api/ngMock/service/$httpBackend for more details
        $httpBackend.expectPOST('http://localhost:7001/factor', data).respond(201, {bar: 'foo'});

        var returnedData;
        datastoreServices.getData(data, DomainService).success(function(result) {
            // Confirm that the returned result contains the expected data
            returnedData = result;
            expect(returnedData).toEqual({bar: 'foo'});
        });

        // Simulate the server response
        $httpBackend.flush();

        // Verify that the success handler was called
        expect(returnedData).toBeDefined();
    });
});

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

Perform an Ajax call just one time

$('#addToCart').click(function () { let csrf = $("input[name=csrfmiddlewaretoken]").val(); let trTable = $(this).parents('div')[1]; let customPrice = $($(trTable).children('div') ...

Creating an href link within a button that is contained within a collapse component

I am grappling with an issue where my collapsed model is displaying more information about clients; however, when I click on the button inside it, instead of getting the specific client's data, I end up retrieving information for all clients. <ion ...

Finding specific data in sessionStorage using an ID or key

I have stored data in sessionStorage and this is an example of how I save the data: $.ajax({ type: 'POST', url: 'Components/Functions.cfc?method='+cfMethod, data: formData, dataType: 'json' }).done(function(ob ...

Error encountered: Unable to access attributes of an object that is not defined (specifically trying to read 'clientX')

Hey there! I'm having some trouble moving figures while moving the cursor. It's strange because I've done the same thing on another page and it worked perfectly: const scaleFactor = 1 / 20; function moveItems(event) { const shapes = do ...

The server nodejs is unable to recognize the dotenv file

This is my very first project with the MERN stack and I'm currently working on pushing it to GitHub. Since I am using Mongoose, I needed to protect the login credentials for my account. After some research, I discovered the solution of using a .env fi ...

UI Grid Experiencing Subpar Vertical Scroll Performance

I've recently started using the updated Angular UI Grid v3.0.7, and I'm facing a challenge with vertical scrolling when implementing a custom cell template. In my grid, there are 15 columns and 83 rows, which is not considered a large dataset. Th ...

How can one effectively manage asynchronous behavior on the client side of a Meteor application?

My focus is on Meteor. I want to connect with the Facebook API through Meteor's HTTP in order to show images on Meteor's client side. I've come across suggestions like Fiber Futures, storing data in Sessions, and triggering a synchronous se ...

Listening to LayersControl.Overlay checkbox clicks in React-Leaflet: A guide

My goal is to dynamically render overlay controls and bind a click event listener to the checkbox of each control in React. However, I am unsure how to provide a React ref to LayersControl or an onClick handler to LayersControl.Overlay. Is there a more eff ...

The asynchronous module has finished even though there is another operation still pending

Currently, I am working on connecting to the Quickbooks API and downloading employee information to save it in my local database. To achieve this task, I am utilizing AngularJS and WebAPI. However, I have encountered an error when attempting to save the in ...

ensure that mocha does not consistently skip tests

When working with mocha, I include several unit tests that incorporate the skip it.skip('login (return photo)', function(done) { ... At times, I need to prevent skipping certain tests, such as right before a deployment. Is there a specific flag ...

Oops! There seems to be an error in the code: SyntaxError: DOM Exception 12 setRequestHeader@[

Currently working on the development of a mobile application for Android and IOS using Phonegap, AngularJS, and CORS_REST. Most headers are functioning well on Android, but encountering issues when testing on iPhone with GapDebug. An example of the authen ...

Load website content in real-time

My website requires dynamic content to be loaded on user interaction. When a user clicks certain elements on the page, information should be retrieved from a file located in the same directory as the webpage and displayed in a designated <div>. My u ...

The functionality of two-way data binding seems to be malfunctioning within the directive

This is my first attempt at creating a directive in AngularJS and I am still learning the ropes. I'm currently experimenting with integrating Bootstrap Year Calendar with AngularJS. The Bootstrap Year Calendar is a jQuery plug-in designed to display ...

Evaluating the criteria and presenting two distinct notifications with setCustomValidity

When validating text fields in an HTML form, I am looking to check two conditions. Currently, the code below checks if the phone number entered is in the correct format and displays a message 'Enter a valid mobile number' if it is incorrect using ...

Error: The function "navigate" has not been declared or defined

Just starting out in reactjs and embarking on a new project. I've successfully implemented a register and login function using firebase, but hit a snag when trying to navigate to a new page like the dashboard upon user login, I encountered this error: ...

The display of AngularJS jQCloud is not rendering correctly within the Bootstrap Modal

I have been utilizing the angularjs plugin for Word Cloud with great success. However, I am experiencing some issues when displaying it within a Bootstrap Modal. It functions properly in an angular ui modal, but not in a Bootstrap Modal. I would really lik ...

Instructions on how to use a keyboard key to activate a dropdown menu item in Bootstrap

Bootstrap 5 navbar features dropdown menus that have underlined hotkeys such as a,n,s, and e. https://i.sstatic.net/bZOaC1kU.png <div class="btn-group"> <button type="button" class="btn btn-danger dropdown-toggle" ...

Retrieving the value of the key from a JSON response

JSON: { "json": { "response": { "servicetype": "1", "functiontype": "10011", "statuscode": "0", "statusmessage": "Success", "data": { "unassignedroles": [ {"role ...

Directive removing input field value from

I'm facing a straightforward Angular issue - it seems like I can't see the solution clearly. The problem arises when I attach a directive to an input field. The intention is to compare new data with old data and display a popup. However, once I ...

Troubleshooting Typescript compilation using tsc with a locally linked node package

In our project using React/React Native with Typescript, we have a mobile app built with React Native and a shared private package that is utilized by both the React Native client and the React frontend. Due to frequent changes in the shared package, we a ...