Evaluating the use of promise in Angular using Jasmine testing

I'm currently troubleshooting whether a method with a promise is being properly called

Below is the snippet of my controller code:

app.controller('StoresListController', function ($scope, StoresService) {

    $scope.getStores = function () {
        StoresService.getStores().then(function (data) {
            $scope.stores = data.data;
        });
    };
    $scope.getStores();

    $scope.deleteStore = function (id) {
        StoresService.deleteStore(id).then(function () {
            $scope.getStores();
        });

    };
})

And this is the testing script I have written:

beforeEach(inject(function($rootScope, $controller, $q) {
        rootScope = $rootScope;
        scope = $rootScope.$new();
        controller = $controller;

        serviceMock = {
            getStores: function(){
                // mock promise
                var deferred = $q.defer();
                deferred.resolve({data : 'foo'});
               return deferred.promise;
            },
            deleteStore : function(){
                var deferred = $q.defer();
                deferred.resolve({data : 'foo'});
                return deferred.promise;
            }
        }
        spyOn(serviceMock,'getStores').and.callThrough();
        controller("StoresListController", {$scope: scope, StoresService: serviceMock});      

    }));  

    it('should call scope.getStores', function(){
        scope.$digest();
        expect(scope.getStores).toHaveBeenCalled()
    });
    it('should call scope.getStores afeter scope.deleteStore', function(){
        scope.deleteStore(1)
        scope.$digest();
        expect(scope.getStores.call.count).toBe(2)
    });

});

I encountered an error message stating "Expected a spy, but got Function." during the first test, and the second one failed as well. Can you help identify what may be causing these issues?

Answer №1

This issue arises because the Spy is added to the serviceMock object instead of being attached to the StoresService. Additionally, you have the option to use the callFake method on the spy in order to simulate the service.

// It's important to note that the StoresService needs to be injected here
beforeEach(inject(function($rootScope, $controller, $q, StoresService) {
    rootScope = $rootScope;
    scope = $rootScope.$new();
    controller = $controller;

    serviceMock = {
        getStores: function() {
            // mocking the promise
            var deferred = $q.defer();
            deferred.resolve({ data: 'foo' });
            return deferred.promise;
        },
        deleteStore: function() {
            var deferred = $q.defer();
            deferred.resolve ({ data: 'foo' });
            return deferred.promise;
        }
    }
    // Creating a Spy for the getStores method
    spyOn(StoresService, 'getStores').and.callFake(serviceMock.getStores);
    // Creating a Spy for the deleteStore method 
    spyOn(StoresService, 'deleteStore').and.callFake(serviceMock.deleteStore);
    // Eliminated the local injection of StoresService
    controller("StoresListController", { $scope: scope });

}));

it('should invoke scope.getStores', function() {
    scope.$digest();
    expect(scope.getStores).toHaveBeenCalled()
});
it('should invoke scope.getStores after invoking scope.deleteStore', function() {
    scope.deleteStore(1)
    scope.$digest();
    expect(scope.getStores.call.count).toBe(2)
});

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

New replacement for routerState.parent feature that has been deprecated in angular2

During my work with Angular 2 rc5, I encountered the following code snippet. this.router.routerState.parent(this.route).params.forEach((params: Params) => { url = params['url']; id = +params['id']; }); I had to resort to th ...

Error: WebView element type is not valid. A valid string was expected

Here is my basic React code : import React from "react"; import { Text, StyleSheet,View } from "react-native"; import { WebView } from 'react-native'; const App = () => { return( <WebView source={{ ...

"Upon calling an asynchronous method within another method, it appears that no progress is being displayed

I've created a `node-js` `db.js` class that retrieves an array of data for me. //db.js const mysql = require('mysql'); var subscribed = []; const connection = mysql.createConnection({ host: 'localhost', user: 'root' ...

In TypeScript, there is a curious phenomenon where private properties seem to be mimicking the

Here is an example of an issue I encountered while working with private properties in TypeScript. I expected that only the public properties would be visible in my object output, similar to normal encapsulation. My aim here is to include the property wit ...

Is the jQuery form plugin not passing any data to Node.js?

Check out the HTML form below: <form id="importForm" enctype="multipart/form-data"> <p> <label for="ownerName">Owner Name<pow class="requiredForm ...

pressing the switch will adjust the size of the container

I am looking to implement a feature where clicking on an icon will resize a div to full screen in the browser. Below is the HTML code I have set up for this functionality, and I am open to suggestions on how to achieve this. <div> <a (click)= ...

Transmitting data from the front end to the server in React/Shopify for updating API information using a PUT request

After successfully retrieving my API data, I am now tasked with updating it. Within my component, I have the ability to log the data using the following code snippet. In my application, there is an input field where I can enter a new name for my product an ...

The hyperlink in the mobile version of the mega menu is unresponsive in HTML

I am encountering an issue with the navigation menu on my Laravel website. The menu links work correctly on the desktop version, but none of the anchor tag links are functioning properly on the mobile version. HTML <div class="menu-container"> < ...

Parsing the CSV file contents according to the specified columns

Currently, I'm involved in a project using AngularJS where I need to extract data from a CSV file column by column using JavaScript. So far, I've successfully retrieved the CSV data and displayed it in the console. While I've managed to sepa ...

How can I integrate an angular-formly template with a custom UI/CSS library?

Seeking advice on incorporating a custom Angular-formly template into my application. I prefer not to use the Bootstrap template as I have my own UI/css library. Should I opt for angular-formly-templates-vanilla or angular-formly-templates-bootstrap and mo ...

jQuery.clone() Internet Explorer issue

I have a scenario where I use jQuery.clone() to extract the html of a page and then append it to a pre tag. Surprisingly, this operation works perfectly fine in Firefox and Chrome, but there's no response when it comes to IE: <!DOCTYPE html> &l ...

Utilizing SASS, JavaScript, and HTML for seamless development with Browser Sync for live syncing and

I've been on a quest to find a solution that covers the following requirements: Convert SASS to CSS Post-process CSS Minify CSS Move it to a different location Bundle all Javascript into one file Create compatibility for older browsers Tre ...

Utilize a personalized useFetch hook in React.js to transmit a POST request and obtain a response

I recently came across a great resource on this website that provided the logic for a useFetch hook. My goal is simple - I want to send a post request and then map the response into a specific type. While this seems like it should be straightforward, I&apo ...

Error: Trying to destructure a non-iterable object with useContext in React is not valid

ERROR [TypeError: Invalid attempt to destructure non-iterable instance. In order to be iterable, non-array objects must have a Symbol.iterator method.] Using UserContext : import React, { useContext, useEffect, useLayoutEffect, useState } from "reac ...

Go back to the top by clicking on the image

Can you help me with a quick query? Is it feasible to automatically scroll back to the top after clicking on an image that serves as a reference to jQuery content? For instance, if I select an image in the "Portfolio" section of , I would like to be tak ...

Troubleshoot: Trouble with selecting the clicked item in AngularJS when using ng-repeat

Is there a way to only delete the selected item from my ng-repeat list instead of deleting all items at once? I can currently delete all items using ng-repeat, but I want to be able to delete just the clicked item. How can I achieve this? https://i.stack. ...

The virtual method 'android.location.Location' was called in error

I'm using WL.Device.Geo.acquirePosition(onGeoLocationSuccess, onGeoLocationFailure, options) from MobileFirst to retrieve a device's location. Initially, everything works smoothly as I successfully obtain the location. However, after clearing t ...

The JavaScript alert message pops up two times consecutively

I encountered an issue while attempting to utilize a module named disclaimer in Drupal 7. The alert message "You must enter the year you were born in." appears twice and then redirects to a URL that should only be accessed after verifying that you are over ...

Triggering jQuery events can be customized by excluding certain elements using the

Is there a way to hide the div "popu" when clicking on the img "tri"? I've tried using .not() since the img is a child of the div popu, but it didn't work. Also, I need to make sure that clicking on the div "textb" does not trigger the hide actio ...

AngularJS simplifies request handling by allowing currying of requests

I am working with three forms within the same container, each triggered by a specific objectId. I want to create a function that can handle all actions related to these objectIds. Unfortunately, I am restricted to using ES5. var applyActions = function( ...