Troubleshooting unexpected errors when testing HTTP services in Angular using httpBackend

The module definition

var module = angular.module('test', []);
module.provider('client', function() {
    this.$get = function($http) {
        return {
            foo: function() {
                return $http.get('foo');
            }
        }
    }
});

module.factory('service', ['client', function(client) {
    return {
        bar: function() {
            return client.foo();
        }
    }
}]);

Essentially, the "client" serves as a wrapper for making HTTP calls, while the "service" wraps around basic features of the client.

I am conducting unit tests on both the provider and service using karma+jasmine. The provider tests are running smoothly, but I'm encountering an issue with the service tests:

describe('service test', function(){
    var service = null;
    beforeEach(function(){
        module('test')

        inject(function(_service_, $httpBackend, $injector) {
            service = _service_;
            $httpBackend = $injector.get('$httpBackend');
        });
    });

    it('should call client.foo via service.bar', function() {
        $httpBackend.expect("GET", "foo");
        service.bar();
        expect($httpBackend.flush).not.toThrow();
    });

});

I am receiving the error message

Expected function not to throw, but it threw Error: No pending request to flush !.
. However, when testing the provider in the same manner, the test passes. Why is that?

Answer №1

When testing your service, it's important to create a mock client and inject it instead of using the real client. You can place the mock in the same file if it's only for this specific test, or in a separate file if you plan on reusing it elsewhere. This approach eliminates the need for $httpBackend since no actual HTTP calls are made, but it does require utilizing a scope to resolve promises.

The mock client:

angular.module('mocks.clientMock', [])
    .factory('client', ['$q', function($q) {
        var mock = {
            foo: function() {
                var defObj = $q.defer();
                defObj.resolve({'your data':'1a'});
                return defObj.promise;
            }
        };
        return mock;
    }]);

Using the mock:

describe('service test', function(){
    var service, mock, scope;
    beforeEach(function(){
        module('test', 'mocks.clientMock');

        inject(function(_service_, $rootScope) {
            service = _service_;
            scope = $rootScope.$new();
        });
    });

    it('should call client.foo through service.bar', function() {
        spyOn(client, 'foo').and.callThrough();
        service.bar();
        scope.$digest();
        expect(client.foo).toHaveBeenCalled();
    });
});

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

What is the process of configuring a custom domain for localhost:3000 in a React application?

"scripts": { "start": "cross-env NODE_PATH=src react-scripts start", "build": "cross-env NODE_PATH=src react-scripts build", } Is there a way to replace localhost:3000 with a custom domain in Rea ...

Stopping an infinite AJAX request to an MVC controller (Revised for lack of suitable reply)

Is there a way to send file chunks to the server asynchronously (to an MVC action in a controller) while ensuring that the requests can be cancelled midway? I am aware of using AJAX abort(), but since the requests are asynchronous, I may have no other opti ...

Are sporadic ajax issues going unnoticed?

Occasionally, when I click a button on my web application, I do not receive any response. This button triggers an ajax call. I suspect that the lack of response may be due to heavy web traffic causing it to time out or something similar. Is there a maxim ...

Tool for controlling the layout of the viewport with Javascript

I have experience using ExtJS in the past to create dashboards, and one of my favorite features is the full-screen viewport with a border layout. This allows for easy splitting of a dashboard into panels on different sides without creating excessive scroll ...

Using Servicenow as a replacement for $sp.getRecord() within a scoped application

When working in a scoped environment in ServiceNow, the global application's method of accessing the current record through $sp.getRecord() is not available. Is there an alternative method to access the current record in a scoped application? Below i ...

Binding variables in JSX with Vue.js scope involves connecting data directly to the template

I am in search of code similar to this: <div v-for="item in items" :key="item"> {{ item }} ... <div v-with:newValue="calculateValue(item)"> {{ newValue }} </div> </div> I'm not sure what to call this pattern, but ...

Swapping out the document.createElement() method for React.createElement()

In a JavaScript library, I utilize document.createElement() to create an HTMLElement. Now, I am looking to develop a React library with the same functionality. My initial thought was to substitute document.createElement() with React.createElement(). There ...

What are the signs that an element was visible on screen prior to navigation?

Recently, I incorporated SlideUp and SlideDown jquery animations into my website. You can check it out by visiting (click the >>>). However, I noticed a small issue where when users navigate to a new page, they have to re-SlideUp the element that ...

Using the codesnippet feature in CKEditor in combination with highlight.js

I am currently experimenting with implementing the highlight.js library in conjunction with the CKEditor addon called CodeSnippet. Although I have successfully integrated the CodeSnippet addon into my CKEditor, the code is not being properly detected, col ...

Setting a variable prior to receiving feedback in Javascript

Uncertain of the appropriate query, but I will attempt to elucidate in my current operational code: var container, loader switch(section){ case 'A': container = $('#list .container') loader = $('#surveylist&apo ...

Transform unidentified individuals into authenticated users using Firebase Authentication for Google

Currently, I am integrating Firebase Auth with VueJS and facing the challenge of converting an anonymous authentication user to a registered user using Google. I have implemented the following code snippet from a reference: fromAnonymousToGoogle: funct ...

Are backbone models causing hiccups in productivity?

Currently, I am working on a GPS data visualizer project using Backbone. Each GPS datum is stored in a backbone model and all of the data is saved in a collection. I am curious to know the kind of overhead involved in this process compared to using an arra ...

Selecting a new image to use as the background on a website by utilizing

While exploring JavaScript, I successfully altered the background color: <script> function changeColor(id,color) { id.style.backgroundColor=color; } </script> <div id="container"> <p> Select a Color to ...

Implement a Basic Custom Shader on a Cube in Three.js

Struggling with applying a basic custom shader to a cube in Three.js. Whenever I attempt to use the shader, the cube mysteriously vanishes. No issues when using a standard Toon or Lambert Material - cube rotates and behaves as expected. Oddly, Orbit Contr ...

Utilizing JavaScript to create a single selection from two Listboxes

Seeking assistance with integrating ASP.NET (C#) code. In my web application, I have implemented two listboxes - one displaying a list of companies fetched from the database (lstCompanies), and the other allows users to filter these companies (lstFilter). ...

``The Vue.js routing system is determined by the incoming data received

Working with VueRouter to navigate to a component based on payload. { path: '/foobar', name: 'foobar', component: foobar, } { path: '/foobar', name: 'foobarSuccess', component: foobarSuccess, query: { ...

Controlling the Output in Typescript without Restricting the Input

I am interested in passing a function as a parameter, allowing the function to have any number of parameters but restricting the return type to boolean. For example, a function Car(driver: Function) could be defined where driver can be ()=>boolean or ( ...

Update the content of a div using jQuery and AJAX by targeting a specific button ID

I am in the process of developing a website that functions as an interactive "choose your own adventure" game. The page will present users with a question along with three different choices represented as buttons. Upon selecting one of the options, jQuery ...

Using event.target.value in find() caused the function to return undefined, but it worked as expected when storing the value in

I am facing a peculiar issue. I am working with a select component that passes a value called "classID" up to a useState. There is an array mapped over the select component which is sent from a NodeJS API and looks like this: [{classID: 371, teacherID: 1, ...

How can React Native efficiently retrieve data from multiple APIs simultaneously?

In my current project, I am incorporating multiple APIs that are interlinked with each other by sharing the same data structure... Below is the code snippet: export default class App extends React.Component { constructor(props) { super(props); } ...