Jasmine spies call through problem detected

I can't seem to get my code to work properly and I keep encountering this error:

TypeError: undefined is not an object (evaluating 'GitUser.GetGitUser('test').then') ...

Check out the code snippets below:

app.controller('HomeController', ['$scope', 'GitUser', function ($scope, GitUser) {
    $scope.name = "user";

    GitUser.GetGitUser('test').then(function (data) {
        console.log(data);
        if (data) {
            $scope.name = data;
        }
    });
}]);
app.factory('GitUser', function ($http) {
    return {
        GetGitUser: function (username) {
            return $http.get('https://api.github.com/users/' + username)
            .then(function success(response) {
                return response.data.login;
            });
        }
    };
});

Take a look at my unit test:

describe('HomeController Unit Test', function () {
    var $controllerConstructor, scope;

    beforeEach(module("AngularApp"));

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

    it('should verify that scope.name is set to test', function () {
        // Act
        GitUser = {
            GetGitUser: function () { }
        };

        spyOn(GitUser, "GetGitUser").and.callThrough();

        GitUser.GetGitUser();

        $controllerConstructor('HomeController', {
            '$scope': scope,
            'GitUser': GitUser
        })

        // Assert
        expect(GitUser.GetGitUser).toHaveBeenCalled();
        expect(scope.name).toBe('test');
    });
});

Answer №1

The issue goes beyond just a missing inject statement ... Check out this revised test:

https://plnkr.co/edit/ZMr0J4jmLPtDXKpRvGBm?p=preview

Here are a couple of key issues: 1) When testing a function that returns a promise, be sure to mock it accordingly (e.g., using return $q.when(..)).

2) When trying to test code executed when your controller is created - the

GitUser.GetGitUser('test').then(function (data) {
        console.log(data);
        if (data) {
            $scope.name = data;
        }
    });

should be enclosed within a function instead:

function init() {
 GitUser.GetGitUser('test').then(function (data) {
        console.log(data);
        if (data) {
            $scope.name = data;
        }
    });
}

and then expose it on your scope:

scope.init= init;

Then, in your test, call the function and validate your assertions. Without encapsulating it in a function, it cannot be tested.

Additionally, regarding mocking and callThrough ... since you are testing the controller (not the service), use callFake instead - have callFake return a Promise with a value (the one to be verified later) to ensure the controller functions correctly.

  var name = 'test';
    // Instead of attempting to mock GitUser, simply use callFake to return a promise
    spyOn(GitUser, "GetGitUser").and.callFake(function() {
      return $q.when(name);
    });

I trust this clarifies everything - the plunker should provide further insight. I will include additional comments there.

Answer №2

It appears that something may have been overlooked

During setup before running the function, ensure to inject dependencies including $controller, $rootScope, and _GitUser:
    $controllerConstructor = $controller;
    scope = $rootScope.$new();
    GitUser = _GitUser;

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

Experimenting with TypeScript asynchronous functions, the async callback was not triggered despite being called within the .then() method

After extensively searching for a solution, I have been unable to find one. The only possibility that comes to mind is that redux-mock-store does not support Promises. Below is the test method in question. import thunk from 'redux-thunk'; impor ...

Developing an HTML table dynamically with JavaScript and incorporating CRM data

I am currently working on my JavaScript file, attempting to create an HTML table. Within this entity's record list are fields such as contractid, name, and address. var filter = "?$select=*&$filter=_plus_franchisee_value eq " + serviceProviderID ...

Loop through the elements retrieved by the `getElementsByName` method in

My goal is to access each node by elementName using the following JavaScript code: function myFunction() { var h1 = document.getElementsByName("demoNode"); for (var i = 0; i < h1.length; i++) { if (h1[i].name == "demoNode") { var att ...

The (window).keyup() function fails to trigger after launching a video within an iframe

Here is a code snippet that I am using: $(window).keyup(function(event) { console.log('hello'); }); The above code works perfectly on the page. However, when I try to open a full view in a video iframe from the same page, the ke ...

What causes the body onload = javascript function to run repeatedly?

Greetings for the absolute beginners out there, just dipping your toes in AJAX. I'm curious to know what exactly triggers the continuous change in divMessage content when the text "myName" is altered. 1) It appears that the Javascript function proce ...

What a great method to execute a button click within the same button click using jQuery!

Here's an example of code that attempts to make an ajax call when a user clicks a button. If the ajax call fails, the button should be reclicked. I've tried this code below, but it doesn't seem to work. $("#click_me").click(function(){ ...

The MongoDB regex is failing to provide the expected outcome

I'm facing an issue with searching data in MongoDB. I have a table with approximately 5000 entries of data that need to be searched based on multiple columns with specific priority criteria. The first priorities for the search are symbol, name, co_nam ...

What could be causing the issue with the .toLocaleTimeString method not properly converting time zones?

I have been attempting to convert timezones based on the current time, but I haven't had success. I tried switching from using date.toLocaleTimeString to date.toLocaleString, but it didn't work. I also tried changing the timezone from America/Den ...

Customizing checkboxes in React with JSS: A step-by-step guide

I'm currently working on customizing CSS using JSS as my styling solution, which is proving to be a bit complex while following the w3schools tutorial. https://www.w3schools.com/howto/howto_css_custom_checkbox.asp HTML: <label class="container"& ...

Vue: The function "priceFilter" is not defined in this context

function sanitizeInput(event) { event.target.value = event.target.value.replace(/[^\d.]/g, ""); event.target.value = event.target.value.replace(/^\./g, ""); event.target.value = event.target.value.replace(/\.{2,}/g, "."); event.targe ...

Executing a Visual Basic subroutine from a jQuery dialog box

Currently, I have a form that includes a jQuery dialog creation. Within this dialog, there is a button generated from an ASP server control that should trigger a function in the code behind when clicked. However, I am encountering an issue where the functi ...

Choose items in a particular order based on the class name of their category

How can I dynamically select and manipulate groups of elements? My intention is to select and modify the msgpvtstyleme elements, then select the msgpvtstyle elements separately and work with them as well. The ultimate goal is to apply classes to these grou ...

Guide to importing a JSON file in a Node.js JavaScript file

I am trying to incorporate a JSON file into my JavaScript code in a Node.js application. I attempted to include it using the "require();" method, but encountered an issue: "Uncaught ReferenceError: require is not defined". ...

Create a gulp task within a callback function that is initiated by calling the filesystem.readdir

When attempting to read the name of the first folder from a directory, and then defining gulp tasks based on that folder, I am encountering an issue. Specifically, after defining a task inside the callback function, the tasks do not get properly defined. T ...

Vue.js is not incrementing the counter as expected

I've encountered an issue with a button that has a click event to increment data value by 5, but instead of adding 5 it is appended by 5. Click here for the code example <div id="react"> <button @click='counter += 5'>Increment& ...

Transfer spoken words into a textbox using the keyboard-microphone feature on an iPad or mobile device

When we tap on a textbox on an iPad or mobile device in a web browser, the keyboard pops up on the screen. We have the option to choose the microphone and dictate the text directly into the input box using our voice instead of typing. Since speech convers ...

Tips for streamlining the use of hidden and visible div elements with concise code

I have been attempting to use the same code for multiple modules on this page, but none of the methods I've tried seem to be effective. I want to avoid endlessly duplicating existing code. document.addEventListener('DOMContentLoaded', fun ...

Troubles encountered during the development of Nextjs/Javascript application

I encountered the following errors while developing my application. I am unsure of the reason behind this issue. I created a fetch request in a separate function and attempted to call this fetch function (which is structured as a custom react hook) within ...

What is the best way to prevent a font awesome icon from appearing in a span during data loading

I am currently working on an Angular 11 application where I have implemented an icon to trigger the loading of a graph. However, I have noticed that there is a delay in loading the graph when the icon is clicked. To prevent users from triggering the icon m ...

Which one should I utilize for a single-page application with login separation: $stateProvider or $routeProvider?

I am trying to build a single page app with login separation, meaning that certain views can only be accessed by authenticated users. My initial code looks like this: .config(function ($routeProvider) { $routeProvider .when('/', { ...