What is preventing me from being able to spyOn() specific functions within an injected service?

Currently, I am in the process of testing a component that involves calling multiple services. To simulate fake function calls, I have been injecting services and utilizing spyOn().

However, I encountered an issue where calling a specific function on one of the services resulted in the error

Error: <spyOn : refreshThings() method does not exist>
. Strangely enough, for other functions within the same service, using spyOn() works perfectly fine.

Below are some relevant code snippets demonstrating how the BasketController relies on the ThingService:

Note: Code has been cleaned up for clarity

Unit Test

describe("BasketController test", () => {
    let $componentController: ng.IComponentControllerService;
    let $scope: ng.IRootScopeService;
    let BasketService;
    let ctrl;
    let ThingService: ThingService;

    // Injections and controller
    beforeEach(() => {
        angular.mock.module("myModule");

        angular.mock.inject(
            (_$componentController_: ng.IComponentControllerService,
                _$rootScope_: ng.IRootScopeService,
                _BasketService_: BasketService,
                _ThingService_: ThingService
            ) => {
                $componentController = _$componentController_;
                $scope = _$rootScope_;
                BasketService = _BasketService_;
                ThingService = _ThingService_;
            }
        );

        ctrl = $componentController('basket',
            {
                '$scope': $scope,
                'BasketService': BasketService,
                'ThingService': ThingService
            }
        );

        spyOn(ThingService, 'refreshThings').and.callFake(() => {
        });
    });

    it('should be testable', () => {
        expect(ctrl).toBeDefined();
    });

Controller

export class BasketController {
    static $inject = ["BasketService", "$state", "AlertService", "$filter", "ThingService"];

    constructor(_BasketService_: BasketService,
        private $state: ng.ui.IStateService,
        private AlertService: AlertService,
        private $filter,
        private ThingService: ThingService) {
            this.BasketService = _BasketService_;
    }

    BasketService: BasketService;
    headerData: Object;
    basketForm: ng.IFormController;
    basket: Basket;
    basketList: Array<Basket>;
    selectAll: boolean;

    toolbarButtons: any;
    columns: [string];
    itemFormatter: any;
    self: any;

    $onInit() {
        // GETs baskets from the service
        this.ThingService.refreshThings();
    }
}

Injected Service

export class ThingService {

    static $inject = ["ApiHttpService", "$q", "AlertService", "StatusThingService"];
    currentThing: Thing;
    thingList: Array<Thing>;

    constructor(private ApiHttpService: IHttpService,
        private $q: ng.IQService,
        private AlertService: AlertService,
        private StatusThingService: StatusThingService) {
    }

    $onInit() {
    }

    getThing(href:string) {

        let defer = this.$q.defer();

        this.ApiHttpService.get(href).then(
            (res:GetThing) => {
                defer.resolve(res);
            },
            (res) => {
                defer.reject(res);
            }
        );

        return defer.promise;
    }

    getAllThings() {

        let defer = this.$q.defer();

        this.ApiHttpService.get("/api/Thing").then(
            (res:Array<GetThing>) => {
                defer.resolve(res);
            },
            (res) => {
                defer.reject(res);
            }
        );

        return defer.promise;
    }

    refreshThings() {
        this.thingList = [];

        this.getAllThings().then(
            (res:Array<GetThing>) => {

                for(let getTemp of res) {
                    let thing = new Thing();
                    thing.fromGet(getTemp);
                    this.thingList.push(thing);
                }
            },
            (res) => {
                console.error("Unable to refresh things");
            }
        );
    }

}

Main.module.service("ThingService", ThingService);

Attempting to spy on refreshThings results in the error message

Error: <spyOn> : refreshThings() method does not exist
, whereas spying on other functions within the service works without issues. This is quite puzzling for me, so any assistance would be highly appreciated. Thank you!

Answer №1

My understanding of Angular is limited, however, it seems that ThingService may be a constructor function or class. To spy on the prototype, you could use

spyOn(ThingService.prototype, 'refreshThings')

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

Make sure to wait for the fetch response before proceeding with the for loop in JavaScript using Node.js

I am facing an issue with my function that connects to a SOAP web service. The problem arises from the fact that the web service has limited connections available. When I use a for or foreach loop to search through an array of items in the web service, aro ...

Error: Unable to access the property 'map' as it is undefined | React, Redux

I'm encountering an issue that says: TypeError: Cannot read property 'map' of undefined. This error is related to trying to map over the array (posts) when it's empty: const postsList = posts.map((postList, i) => { Here is my actio ...

Initiating the accordion feature requires two clicks and triggers an rotation of the icon

I managed to integrate some code I discovered for a FAQ accordion on my website. I am struggling with getting the title to expand with just 1 click instead of 2. Additionally, I would like the icon to rotate when expanding/collapsing, not just on hover. Be ...

Publishing Typescript to NPM without including any JavaScript files

I want to publish my *.ts file on NPM, but it only contains type and interface definitions. There are no exported JavaScript functions or objects. Should I delete the "main": "index.js" entry in package.json and replace it with "main": "dist/types.ts" inst ...

What are the circumstances under which JavaScript GCP libraries return null values?

My current project involves working with GCP and Firebase using typescript. I have been utilizing the provided libraries, specifically version 8 of Firebase, and have encountered some unexpected behavior. For instance (firebase, ver. 8.10.1) import 'f ...

Angular - navigate to the element that was clicked

It seems like there may be a simple solution that I'm overlooking. I have a container element with an ng-repeat on the child element as shown below: <div id="container"> <div class="activity" ng-click="myFunc($element)"> </div ...

Leveraging the power of both TypeScript 2.3 and 2.4 concurrently within Visual Studio 2015.3 on a single machine

Can TS 2.3 and TS 2.4 be used on the same machine simultaneously? For example, I have one project in VS 2015.3 compiling with TS 2.3 and another project compiling with the latest TypeScript version (TS 2.4). I recently installed TypeScript 2.4, which aut ...

Clicking on the image in the Swiper Slider will update the URL

Hi there! I am looking for help with changing the image URL when clicked. Currently, I am using swiper for my image gallery. I want to change this URL: to If anyone has a solution or suggestion on how I can achieve this, please let me know! ...

Can you explain the concept of an anonymous block in JavaScript ES6 to me?

Recently, I came across an article on pragmatists which discussed some interesting ES6 features. However, one concept that caught my attention was the use of an anonymous block within a function. function f() { var x = 1 let y = 2 const z = 3 { ...

Retrieving the value from a concealed checkbox

I have been searching everywhere, but I can't seem to find a solution to this particular issue. There is a hidden checkbox in my field that serves as an identifier for the type of item added dynamically. Here's how I've set it up: <inpu ...

Oops, seems like there was a problem with parsing the

I have encountered an issue when trying to decode the value of a PHP array sent as JSON format. Here is how I created the array: $ads = $atts['ads']; if (sizeof($ads) > 0) { foreach($ads as $social_item) { $sdbr = $social_ ...

Apply ViewEncapsulation.None to all components

I find it frustrating how Angular automatically adds a "_ngcontent-*" in the elements of the HTML page. Since I don't really use that feature, I typically remove it by including "encapsulation: ViewEncapsulation.None" in my component. However, with nu ...

Partial display issue with SweetAlert popup

I am currently working on a personal project using ASP.NET MVC5 and incorporating SweetAlert for managing message alerts. However, I have encountered an issue where the alert message only appears for a brief moment when testing it on an HTML5 button with t ...

Synchronize the scrolling of two tables sharing a common data source to ensure both tables scroll in unison

I encountered some issues while using ui-scroll in my application. My goal is to have ui-scroll function on the same datasource that is used to populate two tables. By scrolling one table, I want the other table created from the same data source to also s ...

Is there an alternative method to incorporate the 'environment.ts' file into a JSON file?

In my Angular application, I need to import assets based on the env configuration. I am attempting to extract the patch information from environment.ts and save it into my assets as a json file. However, I am unsure of the proper method to accomplish this. ...

What are the best ways to integrate markdown into my Vue.js projects?

Is there a way to utilize markdown within the context of vue.js instead of regular HTML paragraphs? ...

What steps can I take to avoid encountering this endless loop?

When passing foo in the arguments of useEffect to use existing array values, it causes an infinite loop because setting new values triggers the f() function again. How can this be resolved? An example of imaginary code is: const [foo, setFoo] = useState&l ...

Unexpected error when using Slack SDK's `client.conversations.open()` function: "User Not Found"

I am currently utilizing the Slack node SDK in an attempt to send private messages through a bot using user IDs: const client = new WebClient(process.env.SLACK_TOKEN); const sendMessage = async (userId) => { try { await client.conversations.open( ...

Troubleshooting: Issues with URL redirection on localhost using Node.js

I've developed a service to verify if the user is logged in, but I'm encountering difficulties running the code on localhost. What could be causing this issue? The redirection isn't functioning as expected, should the code for redirecting t ...

How can I get the class name of the drop destination with react-dnd?

Imagine having this component that serves as a drop target module. import { useDrop } from 'react-dnd'; import './css/DraggableGameSlot.css'; type DraggableGameSlotProps = { className: string, text: string } function Draggable ...