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

Can Ansible and Pulumi be integrated to work together effectively?

Is it possible to create multiple DigitalOcean droplets in a loop and then use Ansible to configure software and security measures on them, similar to how Terraform works? If so, what would the JavaScript/TypeScript code for this look like? I couldn' ...

Ways to address observables in Angular in a manner similar to deferred objects

Transitioning from AngularJS to Angular has posed a challenge for me, especially when it comes to moving from promises to observables. Below is an example of my code in AngularJS: var deferred = $q.defer(), frame = document.createElement('newFrame ...

Utilize axios-cache-interceptor to enforce caching of responses from axios

Is it possible to configure axios to always return a cached response with the help of axios-cache-interceptor? import axios from 'axios' import { setupCache } from 'axios-cache-interceptor' const axiosInstance = axios.create({ timeou ...

SyntaxError: Unexpected symbol

I have an issue with the following code: let op = data.map(({usp-custom-90})=> usp-custom-90 ) When I run it, I encounter the following error: Uncaught SyntaxError: Unexpected token - I attempted to fix it by replacing the dash with –, but t ...

Guide to automatically sending users to a subdomain depending on their IP address location

Currently, my website is built using Node Express and I have a specific requirement. I want to redirect users to different subdomains based on their current location. For example, if a user in Singapore accesses site.com, they should be redirected to sg. ...

ng-include failing to retrieve file name containing UTF-8 character

I encountered an issue with the ng-include directive in the code snippet below. The file name it's trying to access contains a special character, specifically an ñ, resulting in a not found error being displayed. <div ng-include="'{{mainCtrl ...

When working with NextJs, you may encounter a ValidationError indicating that the configuration object is invalid. This error occurs when Webpack has been initialized with a configuration object that doesn't

After upgrading from Next v12 to v12.2.3, I encountered a problem when running "yarn dev" with a new middleware.js file in the root directory: ValidationError: Invalid configuration object. Webpack initialization error due to mismatched API schema. - Deta ...

Discovering the generic type from an optional parameter within a constructor

Looking to implement an optional parameter within a constructor, where the type is automatically determined based on the property's type. However, when no argument is provided, TypeScript defaults to the type "unknown" rather than inferring it as "und ...

Display exclusively the chosen option from the dropdown menu

I am facing an issue with the select input on my webpage. Whenever I try to print the page, it prints all the options of the select instead of just the one that is selected. Can someone please guide me on how to modify it so that only the selected option ...

Tips on modifying the message "Please fill out this field" in the JQuery validation plugin

Is there a way to customize the message "This field is required" in the Jquery form validation plugin to display as "このフィールドは必須です"? Changing the color of the message can be achieved using the code snippet below: <style type="tex ...

The issue with text color not displaying properly within a Material-UI Theme

While designing a color theme using Material-UI, I specified the contrast text as white (#fff). Surprisingly, it seems to work for buttons with the primary color but not for those with the secondary color. I attempted overrides following the suggestions p ...

Ways to organize JSON data from a fetch request into multiple divisions

I have written a JavaScript code to fetch JSON information. I plan on storing this JSON file locally (I downloaded an example file and added a birthdate object for my usage example from https://jsonplaceholder.typicode.com/users) My goal is to parse the r ...

Using Vue.js to dynamically append varying inputs upon user interaction

When I select an option, I want to display different types of inputs based on the selected option. For Example: Select input -> show input fields Select textarea -> show text areas Select boolean -> show radio buttons The Code This is where I choose ...

Is it possible to trigger a reflow prior to initiating a lengthy JavaScript operation?

Ready to face the criticism, I understand that this question has been asked many times before, and I am aware that there are likely more efficient ways to achieve what I'm trying to do... In a JavaScript function, I have a process that can take up to ...

Sending properties of an element to a function within Angular version 4 or 5

Trying to pass attribute values of elements to a function on button click, this is my approach: <div> <ul #list> <li class="radio" *ngFor="let option of options; let j = index" id={{i}}-{{j}} #item> <label><input t ...

The content of btn-id element in Angular is showing as undefined

I have a JavaScript file located at sample/scripts/sample.js and there are 8 HTML files in the directory sample/src/templates/. My goal is to select a button on one of the HTML files. When I tried using angular.elemnt(btn-id).html(), I received an 'un ...

How can you determine the index of a table column in JavaScript when you only know its class name?

I am looking for a way to dynamically hide/show table columns based on their classes, without having to add classes to each individual <td> element. This should be accomplished using classes on the columns themselves. Here is a sample of the table ...

What are some methods to prevent cookies from being overridden?

Just beginning my journey in web development. Currently utilizing asp.net Web API and Angular with token authentication. Every time a user logs in, I set the token in a cookie and send it with each request. Everything has been running smoothly so far, bu ...

Tips for transferring a file to PocketBase using NodeJs

Currently, I am in the midst of a project that necessitates uploading numerous PDF files to a PocketBase collection. All the necessary files are saved on my computer and my goal is to upload them using nodejs along with the PocketBase JavaScript SDK. Howe ...

"Performing validation on a number input by using the ng-change event

Im using a number input that dynamically sets the min and max values based on another form field. I have two scenarios: Level 1: Min = 2, Max = 50 Level 2: Min = 5, Max = 1000 I've set up an ng-change event on the input field to check if the entere ...