Exploring AngularJS unit testing: integrating async and await with Jasmine

I'm currently facing a challenge with unit testing my Angular service using the async/await keywords in the respective (Jasmine) unit tests below. The test for the built-in Promise is functioning correctly, however, I am encountering difficulties in getting the Angular $q counterpart to work.

  • Angular: 1.6.5
  • Jasmine: 2.7.0
  • (Headless) Chrome on MacOS: 60.x

angular
  .module('asyncAwaitTest', [])
  .factory('xService', xServiceFactory);

function xServiceFactory(
  $q,
  $timeout
) {
  return {
    getXAfter1Sec() {
      return new Promise(resolve => setTimeout(() => resolve(43), 1000));
    },
    getXAfter1SecWithAngular$Q() {
      const deferred = $q.defer();

      $timeout(() => deferred.resolve(43), 1000);

      return deferred.promise;
    }
  };
}

jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;

describe('asyncAwaitTest: x service', () => {
  let $timeout;
  let xService;

  beforeEach(() => {
    module('asyncAwaitTest');

    inject(
      (
        _$timeout_,
        _xService_
      ) => {
        $timeout = _$timeout_;
        xService = _xService_;
      }
    );
  });

  it('should work', async (done) => {
    const x = await xService.getXAfter1Sec();

    expect(x).toEqual(43);

    done();
  });

  it('should work, as well. Why isn't it working?', async (done) => {
    const xPromise = xService.getXAfter1SecWithAngular$Q();

    $timeout.flush();

    const x = await xPromise;

    expect(x).toEqual(43);

    done();
  });
});

Fiddle link provided here: https://jsfiddle.net/glenn/gaoh6bvc/

I've attempted to search on Google for solutions, but unfortunately, I haven't found a clear resolution yet 😞

Answer â„–1

If you want to simplify your test, consider creating a helper function that converts promises from $q to native promises. Take a look at an example here.

it('Why not try this approach as well?', async (done) => {
  const xPromise = toNativePromise(xService.getXAfter1SecWithAngular$Q());

  $timeout.flush();

  const x = await xPromise;

  expect(x).toEqual(43);

  done();
});

function toNativePromise(promise) {
  return new Promise((resolve, reject) => {
    promise.then(val => {
      resolve(val);
    }, err => {
      reject(err);
    });
  });
}

Answer â„–2

async operations rely on native promises, whereas AngularJS utilizes $q promises. The await keyword serves as a shorthand for linking a promise with then. In tests, $q promise chains are executed during the digest cycle.

Attempting to address this issue using

await xPromise;
$rootScope.$digest();

is ineffective because $rootScope.$digest() doesn't get evaluated until after its execution, leading to a lingering promise.

It is not recommended to test AngularJS using async..await methodology since Angular was primarily designed for synchronous testing.

An alternative approach could be

it('...', () => {
  ...
  xPromise.then(x => {
    expect(x).toEqual(43);
  });
  $rootScope.$digest();
});

Alternatively, promises can be streamlined with jasmine-promise-matchers:

it('...', () => {
  ...
  expect(xPromise).toBeResolvedWith(43);
  $rootScope.$digest();
});

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

Mastering Puppeteer: Tips for Successfully Submitting Forms

Can you use puppeteer to programmatically submit a form without a submit input? I have been successful with forms that include a submit input by using page.click('.input[type="submit"]'), but when the form does not have a submit input, focusing o ...

Managing integer values in controllers with .NET Core 6

I have a simple API controller where I can manipulate any model in my design, but I'm having trouble handling int or string values. Here's a snippet of my code: [Route("Get"), HttpPost] public async Task<JResultModel> Get(int id) { if ...

Sorting data in Javascript can be done efficiently by utilizing the .filter method

Can someone help me identify what I might be doing incorrectly? I have a chained filter under computed that is giving me an error message stating 'product.topic.sort' is not a function. My intention is to use 'select' to provide sortin ...

The jQuery toggle functionality seems to be malfunctioning

I have created a form that should toggle (hide and show) with the click of a button, but for some reason it's not working. Can someone please take a look at my code below and let me know what I'm doing wrong? $(document).ready(function () { ...

The navigation controller, responsible for updating navbar values, is only executed once

My goal is to construct a simple Angular application and familiarize myself with the basics. To start, I'm utilizing Yeoman's angular-generator for scaffolding. This generator comes with a predetermined .config featuring $routeProvider, which I ...

Enhancing the capabilities of my search and select filter beyond the boundaries of ng-app in AngularJS

In the controller, I have a directive that lists items using data from an API call. The HTML code for this is: <div ng-app="WWnetworkEvents"> <ul ng-controller ="networkEventsCtrl"> <networkevent-directive></networkevent-directiv ...

The Angular directive is failing to refresh the data on the Google Map

I created a directive called "myMap" to incorporate a Google map into my application. However, I am facing an issue when attempting to update the longitude and latitude values for a different location using a controller function. The directive does not ref ...

Configuring Firefox settings in Nightwatch

Is there a way to set Firefox preferences in nightwatch? I am trying to achieve the same thing in Java using nightwatch. To set Firefox preferences in nightwatch, you can use the following code snippet: FirefoxProfile profile = new FirefoxProfile(); prof ...

Exploring deeply nested objects within Express by iterating through them

I am trying to figure out how to iterate through objects in Express.js. I can retrieve information from the JSON file, but when I attempt to loop through it, I keep getting an error saying that it's not defined. What could I be missing here? My goal ...

Analyzing and refreshing the data entries in firebase database

https://i.stack.imgur.com/ZMjck.png I have been attempting to modify my Username password group name. However, the update process is not successful. I am looking for a way to compare data before updating fields, but I am unable to find a suitable method. ...

JavaScript and CSS tabs with smooth transition effect

I want to create tabs that smoothly fade between each other when switching. The code I have works, but there's a slight issue. When transitioning from one tab to the previous one, there is a momentary glitch where the last tab briefly changes state be ...

What is the best way to get rid of a connect-flash notification?

I'm having trouble removing the message (with the username displayed) after logging out by pressing the logout button. Every time I try to press the logout button, it just refreshes the page without any action. I want to stay on the same page and not ...

Contrasting the variance between binding through the [] syntax and abstaining

There is a unique custom my-table element that has its row property bound to the host component. There are two different ways in which HTML can be inserted: <my-table [rows]="displayEntriesCount"></my-table> and alternatively: <my-table r ...

Implementing a JavaScript function that uses the AJAX method to confirm and update

I am currently attempting to update a database using the JavaScript confirm() function in combination with AJAX. My goal is to have "accepted_order.php" run if the user clicks "OK," and "declined_order.php" run if the user clicks "Cancel," all without caus ...

Is it appropriate to refer to a single page application as a web 3.0 application?

As time progresses, we are witnessing the rise of more and more single page applications or frameworks such as new twitter and Sammy. It appears to be a significant advancement where we move away from generating code on the server side, with servers actin ...

When encountering an issue while invoking a function in Vue.js, an internal error may occur, as evidenced by the message: "new Http

Currently, I am in the process of developing an application and encountering an issue where I am unable to comprehend a cryptic error message that keeps popping up. If you'd like to see the error itself, you can check it out here. Below is my form.vu ...

Attempting to implement a disappearing effect upon submission with the use of JavaScript

I am currently working on implementing a disappearing form feature for a small web application. The idea is that once the initial form is submitted, it will be replaced by a new form. While my current code somewhat works, it only lasts for a brief moment b ...

Traverse a collection of nested objects containing arrays as their values

Consider the following object: { "apples": [ "one", "two" ], "oranges": [ "three", "four" ] } If I want to find the value four within this object, how can I do so efficiently? Would a loop work, like the one shown below? for (var ...

When I attempt to conceal the filter within mat-table using *ngIf, I encounter an issue where I am unable to read the property 'value' due to it being

After creating a mat-table, I encountered an issue when trying to show and hide my input filter area using a button. If I use *ngIf="showInputFilter" to hide the filter area, I receive the error message Cannot read property 'value' of u ...

What is the process for obtaining a compilation of JavaScript files that are run when an event is triggered?

How can I generate a list of all the JavaScript files that are triggered when a button is clicked or an input field is selected in a complex system? Is it possible to achieve this with Chrome DevTools, or are there alternative solutions available? If Chro ...