Experimenting with an Angular Controller that invokes a service and receives a promise as a

I am currently in the process of testing an angular controller that relies on a service with a method that returns a promise. I have created a jasmine spy object to simulate the service and its promise-returning method. However, my mock promise is not returning the expected result for some reason.

Below is the code for my controller and service:

(function(){
'use strict';
angular
    .module("supportPortal",[])
    .service('TipsService' ,['$http' ,TipsService])
    .controller('TipsCtrl', [ 'TipsService', TipsCtrl]);

function TipsService($http) {
    this.path = 'api/bondtipsfactor';
    this.tipsFactors = [];
    this.getMinMaxDates = getMinMaxDates;
    this.getData = getData;

    function getMinMaxDates() {

        var self = this;
        var promise = $http.get(self.path + '/minmaxdate').then(function (result) {
            return result.data;
        });
        return promise;
    }
}

function TipsCtrl(TipsService) {
/* jshint validthis:true */

 var vm = this,
 svc = TipsService;
 vm.title = 'TipsCtrl';
 vm.setMonths = setMonths;
 var today = new Date();
 vm.minMonth = 1;
 vm.minYear = today.getFullYear();
 vm.maxYear = today.getFullYear();
vm.maxMonth = today.getMonth() + 1;
vm.years = [];
vm.months = [];
vm.selectedYear = 2014;
vm.selectedMonth;
activate();
function activate() { 
    svc.getMinMaxDates().then(function (data) {
        console.log(data);
        var minDate = new Date(data.MinDate),
                maxDate = new Date(data.MaxDate);
        maxDate.setMonth(maxDate.getMonth() + 1);
    vm.minMonth = minDate.getMonth();
    vm.minYear = minDate.getFullYear();
    vm.maxMonth = maxDate.getMonth();
    vm.maxYear = maxDate.getFullYear();
    for (var i = vm.minYear; i <= vm.maxYear; i++) {
      vm.years[i - vm.minYear] = i;
    }
  });
}

function setMonths(year) {
    var startMonth = year === vm.minYear? vm.minMonth: 1,
            endMonth = year === vm.maxYear ? vm.maxMonth : 12;
    vm.month=[];
    for (var i = startMonth; i <= endMonth; i++) {
        vm.months[i - startMonth] = i;
    }
}
}
})();

Here is the test code:

describe("TipsCtrlSpec", function () {
describe("TipsCtrl", function () {

    var ctrl, service, $q, $controller;
    beforeEach(angular.mock.module("supportPortal", function($provide) {
        service = jasmine.createSpyObj("TipsService", ['getMinMaxDates']);
        $provide.value("TipsService", service);
    }));

    beforeEach(inject(function (_$controller_, _$q_, _TipsService_) {
        service = _TipsService_;
        $q = _$q_;
        $controller = _$controller_;
    }));

    function createController(resolve)
    {
        var deferred = $q.defer();
        service.getMinMaxDates.and.returnValue(deferred.promise);
        ctrl = $controller("TipsCtrl", {
            TipsService: service
        });
        if (resolve) {
            deferred.resolve({
                MinDate: "01/01/2013",
                MaxDate: "01/01/2014"
            });
        } else {
            deferred.reject();
        }
    }

    it("activate sets min max dates", function () {
        createController(true);
        expect(ctrl).toBeDefined();
        expect(service.getMinMaxDates).toHaveBeenCalled();
        expect(ctrl.minYear).toBe(2013);
    })
});
});

Check out the live code here.

Answer №1

When performing unit tests with ngMock, it is important to maintain the flow of the tests synchronously and manually trigger the digest cycle for promises to be resolved.

To achieve this, you can use $rootScope.$digest():

it("verify data loading", function() {
  loadTestData();
  $rootScope.$digest();
  expect(data).not.toBeNull();
  expect(service.getData).toHaveBeenCalledTimes(1);
  expect(data.length).toBeGreaterThan(0);
});

Check out the demo: http://example.com/demo

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

How to properly display an Angular Template expression in an Angular HTML Component Template without any issues?

When writing documentation within an Angular App, is there a way to prevent code from executing and instead display it as regular text? {{ date | date :'short'}} Many sources suggest using a span element to achieve this: <span class="pun"&g ...

Is there a way to delay the start of an ajax function until a few moments after the user

Good evening, I am interested in implementing a new feature using Ajax. Specifically, I would like to introduce a delay of 2 seconds after the user finishes typing before triggering the search function, as opposed to using "onkeyup". Note: This modificati ...

"Exploring the world of server-side and client-side MVC frameworks

I recently embarked on learning ASP.Net MVC and have encountered some puzzling questions regarding the MVC framework - particularly, whether it leans more towards client-side or server-side operation. I understand if these queries seem basic, but I'd ...

nodejs callbacks and their return values

Hey guys, I'm having trouble resolving an issue with a JavaScript callback return. Here's the function in question: //Function to get user's contact list function get_contact_list(data) { //Retrieve user ID based on ...

Starting Unit Testing in Django: Comprehensive Guide to Initializing Database

As I delve into Test Driven Development with Django, a hurdle I encounter is the need to populate the database with various data before running tests. This includes creating users, departments, and assigning permissions. Initially, I attempted using fixtur ...

Halting Execution After Placing an Object in Three.js Scene with Javascript

It seems like a simple task, but I've been struggling with it for days. How can I add objects to a scene with a pause between each addition? Inside a loop{ I call the make_obj function() then I call the wait function() } The issue is that the pr ...

Implementing a NextJS client component within a webpage

I am currently working with NextJS version 14 and I am in the process of creating a landing page. In one of the sections, I need to utilize the useState hook. I have specified my component as "use-client" but I am still encountering an error stating that " ...

Do we require Node JS for developing Angular JS applications? If so, what is the rationale behind it? And why is Node JS not needed in a production environment?

Do you need Node.js to develop an AngularJS application? If so, what is the reason for that requirement? I have come across some articles stating that Node.js is necessary when building an AngularJS app, however, it is not needed in production. I am puzzl ...

Ways to display a component using *ngIf else

As a beginner in angular, I decided to create a simple app to help me learn the basics. The concept of my app involves two players entering their names in separate input fields. Once they click a button, the game begins and displays their names along with ...

Guide on verifying Unicode input in JavaScript?

I am looking to create a form where the user can only input Khmer characters (Unicode characters) and display an alert if they input anything else. Khmer Name: <input type="text" class="namekh" name="namekh"> To achieve this, here is a snippet of m ...

Are the fetch functions within getStaticProps and getServerSideProps equivalent to the fetch API native to web browsers?

I've been working with Next.js for some time now and I'm questioning the fetch API used in both getStaticProps and getServerSideProps. Below is my understanding of these functions: getStaticProps runs during build time and ISR getServerSidePro ...

What is the best way to handle query string parameters when routing in Next.js?

One of the challenges I am facing is related to a URL structure like this: bar?id=foo When I navigate to this URL using router.push('bar?id=foo'), everything works perfectly. However, if I directly access the route in the browser, the query st ...

Tips for creating a function that utilizes a select option value

I'm struggling with a form that includes two select inputs. I want the second input to only be enabled if the first one has been selected. I attempted using an onclick event, but it didn't work out as expected. Can anyone provide assistance? (apo ...

React.js Filter Component

I'm currently trying to create a filter for my "localtypes", but I'm encountering an issue where the console in my browser is displaying an empty array. My goal is to access the localtypes properties of the API that I am working with. I attempte ...

Verifying the absence of query parameters in AngularJS forms

I have been working on a project that involves passing query parameters to the backend for searching purposes. These parameters are passed using the AngularJS $http.get method. Some of these parameters are not mandatory for the search, so I would like th ...

"Enhance Your Highchart Experience by Adding Hyperlinks to Every Segment of Your Stacked Bar

I am seeking to assign a specific link to each segment of a stacked 100% bar chart. Check out this demo of a stacked bar chart: Here's what I am trying to accomplish: Please visit , input data in the left table, and submit it. After submission, you ...

Take the inputs, calculate the total by multiplying with the price, and then show

I'm in the process of developing a simple PHP form for an online t-shirt order system. Most aspects are running smoothly, but I'm facing issues with the final calculations. My goal is to combine the quantities based on sizes, multiply them by the ...

Is your YQL JSON script failing to provide the expected output?

Here is a script that I have copied almost directly from this. Why is it that the code below does not seem to return anything? ajax.html: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html dir="lt ...

Exporting all components using require: A complete guide

Currently, I am working on a Vue js application where I am tasked with exporting all the files and components from a specific directory. These files/components need to be imported into a separate file named paths.js. If I use the require function to impor ...

What's the best way to track changes in multiple form fields simultaneously in Angular?

Situation I have a form with 8 fields, but I want to monitor changes in just three of them to apply the same function. I don't want to set up individual subscriptions for each field like this: this.headerForm.get('start').valueChanges.subsc ...