Utilize the synchronization feature of ES6 Promises in Jasmine with the then/catch method

I have an angular controller that needs to be tested. This controller utilizes a service to fetch data from a server, and the service returns ES6 Promises.

function MyController($scope, MyService) {
  $scope.doSomething = function () {
    MyService.foo().then() {
      whatever...;
    };
  };
};

When writing my Jasmine test, I mock the service which also returns Promises:

var resolve;
var reject;
createPromise = function () {
 return new Promise(function (_resolve, _reject) {
    resolve = _resolve;
    reject = _reject;
  });
};

var myServiceMock = {
  doSomething: jasmine.createSpy('doSomething').and.callFake(createPromise)    
};

beforeEach(module('someApp', function ($provide) {
  $provide.value('MyService', myServiceMock);
}));

To check on my controller, I manually trigger the global resolve (or reject) with or without parameters.

it('should call the service', function () {
  $scope = $rootScope.$new();
  controller = $controller('MyService', { $scope: $scope });
  controller.doSomething();
  myService.resolve();
  expect(whatever...);
});

The issue arises when the resolve call is asynchronous. This means I am testing my expected outcome while the then function is still running.

After attempting to replace Promises with a simple custom object for synchronous resolution in my mocks, I found that re-implementing Promises' specific rules, such as .then(), .catch(), .then() patterns, was cumbersome.

Is there a simpler, synchronous way to test this type of scenario in Jasmine?

Answer №1

Inform Jasmine that your test is asynchronous and must wait for completion before determining failure. Add a done parameter to the spec declaration (it call) and invoke done at the end of expectations:

it('should execute the service', function (done) {
  $scope = $rootScope.$new();
  controller = $controller('MyService', { $scope: $scope });
  var promise = 
    controller.doSomething()
      .then(function() {
         expect(whatever...);
         done();
      });

  myService.resolve();
});

An alternative method to automatically resolve mocks is to utilize Promise.resolve:

doSomething: jasmine.createSpy('doSomething').and.returnValue(Promise.resolve())

In this way, you no longer need to call myService.resolve as the mock will automatically return a resolved promise.

Consider using the jasmine-promises module for simplifying promise handling and ensuring error reporting for easier debugging. With jasmine-promises, the code would look like this:

it('should execute the service', function () {
  $scope = $rootScope.$new();
  controller = $controller('MyService', { $scope: $scope });

  return controller.doSomething()
      .then(function() {
         expect(whatever...);
      });
});

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

ajax receives an empty responseText after sending intermediate data to Python on the backend

Initially, the frontend passed an identification to the backend. The backend utilized this identification to retrieve data from the database. The extracted data then underwent additional processing on the backend before being sent back to the frontend. Be ...

What is the process for updating button text upon clicking in Angular?

To toggle the text based on whether this.isDisabled is set to false or true, you can implement a function that changes it when the button is clicked. I attempted to use this.btn.value, but encountered an error. import { Component } from '@angular/core ...

What is the reason for the absence of styles in index.html when accessing the local server?

When using node.js to open the server, I encountered an issue where the styles are not displaying. Strangely, when opening index.html directly in the browser, all the styles show up correctly. What could be causing this discrepancy? index.html <!doctyp ...

Updating component (`App`) during the rendering of another component is not allowed

I have encountered an issue with a react component that I am struggling to resolve. It involves a radial knob control, similar to a slider, and I am trying to achieve two main objectives: Adjust the knob and pass its value up to the parent component for ...

Select any menu option to return to the one-page layout and then scroll down to find the location

I'm wondering if there is a way to navigate back from an external page to a specific section on my one-page website with a fixed menu? On my one-pager website, I have a fixed menu that includes a "apply for a job" button. When clicked, it takes users ...

ways to run php script based on screen resolution or size

I have 2 php files that I need to execute based on screen size. include_once('large.php'); include_once('small.php'); The condition is to run large.php when the screen size is greater than 992px, and small.php when the screen size is ...

What is the best way to determine if an item in an array is not empty?

Let's consider an array: arr = [{}, {}, {}, {}] If we want to determine the length of the array by counting only objects that contain at least one property, we can do this: [{}, {name: "Manchester United", odds: 3}, {}, {}] // 1 [{}, {name: "Liver ...

What is the correct way to invoke a function contained within an object that is stored in an array?

I've encountered a problem with my program. I'm attempting to invoke a function that is part of an object stored in an array, but I'm having difficulty calling the function correctly. //Initialize Array for Storing Projects let allProjects ...

Retrieving rows from a MySQL table that contain a specified BIGINT from an array parameter

I've encountered a problem with mysql while using serverless-mysql in TypeScript. It seems like my query might be incorrect. Here is how I am constructing the query: export default async function ExcuteQuery(query: any, values: any) { try { ...

access the database information within the fullcalendar plugin

I've been exploring the calendar code on arshaw/fullcalendar and made some modifications, but I'm still unsure how to link JavaScript with a database. Here is the original code: $(document).ready(function() { var date = new Date(); var d = dat ...

Challenges of aligning a modal overlay in the middle of mobile screens

Currently, I am developing a website and encountering a specific issue with the modal structure. When viewing it on Codepen using Chrome devtools and toggling the device toolbar to simulate mobile screens, everything appears fine. However, when opening the ...

Using an array of objects to set a background image in a Bootstrap carousel using jQuery: a step-by-step guide

I have an array of items, each containing a background property with a URL to an image. Here is my array: Here is the HTML structure: <div id="myCarousel" class="carousel slide" data-ride="carousel"> <ol class="carousel-indicators">&l ...

Are we retrieving multiple APIs the right way?

Looking for some guidance on fetching two APIs in React. I have created two functions to handle this task and called them simultaneously within another function. Should I stick with this approach or move the API calls to componentDidMount? Additionally, I& ...

Leverage Typescript to convert string literal types to uppercase

type x = 'first' | 'second' I am looking to create a type y that is similar to this: type y = 'FIRST' | 'SECOND' Here is what I attempted: type x = 'first' | 'second' type y = {[key in x]: key[& ...

Converting an object of objects into an associative array using Javascript and JSON

Using AngularJS, I am sending this data to my API : $http.post('/api/test', { credits: { value:"100", action:"test" } }); Upon receiving the data in my nodeJS (+Express) backend, it appears as follows : https://i.stack.imgur.com/NurHp.png Why ...

Incorporate create-react-app with Express

Issue - I am encountering a problem where I do not receive any response from Postman when trying to access localhost:9000. Instead of getting the expected user JSON data back, I am seeing the following output: <body> <noscript>You need to ...

Navigate through the elements of an Ext.form.CheckboxGroup using Ext JS

Currently, I am working with an Ext.form.CheckboxGroup that contains multiple items of Ext.form.Checkbox. I am wondering if there is a way to iterate through each item within the Ext.form.CheckboxGroup? I attempted the code below without success: for ( ...

I'm puzzled as to why a div tag suddenly becomes invisible when I attempt to link it with a v-for directive in my code

I am facing an issue with the div tag assigned to the log class. My objective is to populate the text using data retrieved from the API response. However, when I attempt to include the v-for directive, the entire div mysteriously disappears from the brow ...

Currently working on integrating a countdown timer using the Document Object Model (DOM)

Is it possible to create a timer in the DOM without using any JavaScript? I currently have a JavaScript code for the timer, but I want to convert it to work directly with the DOM without needing to enable JS. Any assistance would be greatly appreciated! ...

IE7 is throwing an error saying "Object Expected" when handling the JSON response. This issue does not

Just when I thought I was ready to launch my webapp, IE7 decides to throw a wrench in my plans! I am using the JQuery Form plugin for uploading data to my server. Everything works perfectly on Chrome and Firefox, but IE7 is giving me an "Object Expected" ...