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

Issue with parent-child communication in React.js causing malfunction

I am facing an issue with maintaining state between two different JavaScript files using React. The parent class, break.js, is defined as follows: export default function AlertDialog(props) { const [demoOpen, setDemoOpen] = React.useState(true); ...

Leverage VueJS and VueX to seamlessly integrate firebase 9 functions within my application

I am currently in the process of developing a blog application using Firebase version 9, VueJs version 3, and VueX. All functionalities such as user registration and authentication are working smoothly. However, I encountered an error when attempting to a ...

Sending a PHP variable to a JavaScript function

When attempting to pass a value to a JavaScript function by clicking a link, I encountered an error message: Uncaught SyntaxError: Unexpected identifier The following is the code snippet: <?php include_once("php_includes/check_login_status.php") ...

Struggling to get the AJAX code functioning correctly

Embarking on my journey with AJAX, I decided to test a simple example from the Microsoft 70515 book. Surprisingly, the code doesn't seem to be functioning as expected and I'm at a loss trying to figure out why - everything appears to be in order. ...

Add an image to a div element and determine its height, then apply the height to the CSS property

Here is my JavaScript code that utilizes jQuery: $(".article_big_photo").click(function() { $('#screen').css({ opacity: 0.5, 'width':$(document).width(),'height':$(document).height()}); $('#screen').show() ...

Tips for resolving the issue of 'defineExpose' method being undefined in Vue3

Struggling to pass a method from child to parent; unfortunately, the defineExpose() method seems to be malfunctioning. Could anyone provide guidance on what might be going wrong? For additional context, feel free to check out my previous question <scri ...

Manipulating visibility of an input tag using JQuery

Having a simple input tag: <input id="DAhour" type="number" style="width:50px; font-size: xx-small; visibility:hidden"> Initially, the input tag is set to be hidden. Upon changing a combobox to a specific index, it should become visible. Despite su ...

Is there a method to delay HTTP requests until the number of pending requests drops below a certain threshold (N)?

I'm in the midst of a project that involves allowing users to upload multiple files simultaneously. However, sending out numerous requests all at once can overwhelm the server and trigger a 429 (Too Many Requests) error for those requests. Is there a ...

What is the best way to validate user input in a CRUD application built with the MEAN stack?

Currently, I am developing a CRUD application and the snapshot above showcases its design. I have successfully implemented validation for updating in this application after referring to a guide on Stack Overflow. Despite my efforts, I have been unable to ...

I tried running the sample program from the website in mongoose, but I encountered a persistent error: "TypeError: fluffy.speak is not a function."

const mongoose = require('mongoose'); main().catch(err => console.log(err)); async function main() { await mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true }); console.log("Connection successfu ...

What is the best way to ensure data validation occurs only when a button is clicked

In my project, I am faced with the challenge of validating inputs only after a submit button is clicked. However, I have noticed that the required rule is being activated after losing focus. This issue arises while using VeeValidate in Vue.js. Here is the ...

Dealing with encoded base64 audio and retransmitting it to Google: a comprehensive guide

I managed to successfully capture audio using the browser's microphone, convert it to base64 encoding, and then sent it over to my node.js application with the intention of further processing it through Google Speech-to-Text API for transcription. How ...

Arrange the JSON object according to the date value

I am working on a JavaScript project that involves objects. Object {HIDDEN ID: "06/03/2014", HIDDEN ID: "21/01/2014"} My goal is to create a new object where the dates are sorted in descending order. Here's an example of what I want: SortedObject ...

What is the Angular2 equivalent of the AngularJS $routeChangeStart event?

During our time working with AngularJS, we utilized the $routeChangeStart/End event in the $rootScope to monitor changes in the route object. What is the equivalent method for monitoring route changes in Angular2? How can we achieve the same functionality ...

Troubleshooting a challenge with binding in the AngularJS plupload directive

I have been working on creating a directive for plupload, and so far I have made progress. Initially, I was able to get the file upload feature working without using the directive (controller and standard HTML). After adding the directive, the HTML rendere ...

Can Keyboarddatepicker automatically format the date?

We are utilizing material ui Keyboarddatepicker in our React application and have specified the date format using props as format=DD/MMM/YYYY, resulting in dates being displayed like "10/12/2020". The date picker functions perfectly when selecting a date. ...

What is the best way to implement ES2023 functionalities in TypeScript?

I'm facing an issue while trying to utilize the ES2023 toReversed() method in TypeScript within my Next.js project. When building, I encounter the following error: Type error: Property 'toReversed' does not exist on type 'Job[]'. ...

You are not able to access the instance member in Jest

My first encounter with Javascript has left me puzzled by an error I can't seem to figure out. I'm attempting to extract functions from my class module in order to use them for testing purposes, but they remain inaccessible and the reason eludes ...

Need a jQuery function that updates the 'id' after clicking on a specific div? Here's how to do it!

I need help simplifying my current situation. Step 1: I want to increment the variable "count" by 1 every time a specific div is clicked. Step 2: After updating "count", I want to utilize it in another function. This function involves copying the value f ...

Through the implementation of JavaScript, the element's class is dynamically altered

While working on my project, I encountered an issue with implementing a change in the class of an element using JavaScript. The problem is that when I click on the home page, the last page does not get deselected. Here is my current JavaScript code: const ...