Testing Angular when mixing $q and ES6 promises
Asked Answered
F

1

7

I am having a problem where my code mixes ES6 Promises with Angular promises, and it works in production by I cannot write unit tests that pass.

This code snippet demonstrates two instances where Jasmine unit tests will fail, but the code works fine in production:

  // An angular $q promise
  var f1 = function() {
    return $q(function(resolve, reject) {
      resolve('This is function 1!');
    });
  }

  // An ES6 promise
  var f2 = function() {
    return new Promise(function(resolve, reject) {
      resolve('This is function 2!');
    });
  }

  // An angular $q.all() promise, attempting to resolve a $q and ES6 promise.
  var s1 = function() {
    return $q.all([f1(), f2()]).then(function() {
      return '$q resolved both promises!'
    });
  }

  // An ES6 promise attempting to resolve a $q and an ES6 promise.
  var s2 = function() {
    return Promise.all([f1(), f2()]).then(function() {
      return 'ES6 resolved both promises!'
    });
  }

The tests look like:

describe('Testing mixed ES6 promises and Angular $q', function() {
  var $scope = null;
  var service = null;

  //you need to indicate your module in a test
  beforeEach(module('plunker'));

  beforeEach(inject(function($rootScope, _testService_) {
    $scope = $rootScope.$new();
    service = _testService_;
  }));

  afterEach(function() {
  });

  it('should resolve f1', function(done) {
    var t1 = service.f1();
    t1.then(function() {
      done();
    });
    $scope.$apply();
  });

  it('should resolve f2', function(done) {
    var t1 = service.f1();
    t1.then(function() {
      done();
    });
    $scope.$apply();
  });

  it('should resolve s1', function(done) {
    var t1 = service.s1();
    t1.then(function() {
      done();
    });
    $scope.$apply();
  });

  it('should resolve s2', function(done) {
    var t1 = service.s2();
    t1.then(function() {
      done();
    });
    $scope.$apply();
  });

});

This Plunker has a working demonstration: http://plnkr.co/edit/xhRc7O

Notice that the first 2 tests pass because they are straightforward ES6 or $q promises.

Then notice that every other tests fails because I mix ES6 and $q promises in different ways.

Finally, notice that in the controller I demonstrate that two FAILING tests do in fact work in production.

Why does Angular not let me mix ES6 and $q promises in my tests, yet have no problems in production code?

Francefrancene answered 27/11, 2015 at 22:17 Comment(1)
Did you try starting on issue? Maybe it's a bug and you have designed a very straightforward way to reproduce it.Syconium
T
1

I also run into this problem with my unit tests. Until I have an explanation to the issue and a proper solution I use a workaround:

    if (window.Promise !== $q) {
        window.Promise = $q;
    }
Tide answered 11/4, 2016 at 15:18 Comment(2)
This worked for me, but I created this issue on Jasmine in the hopes that they will create a proper fix: github.com/jasmine/jasmine/issues/1200Jew
@Jew Don't forget to restore it to the original value in afterEach function. Otherwise other tests may fail because of $q created in different angular context.Tide

© 2022 - 2024 — McMap. All rights reserved.