Steps to reproduce:
git clone [email protected]:angular/angular-seed.git
cd angular-seed
npm update
bower update
cat << 'EOF' > app/view1/promise_test.js
'use strict';
describe('Promise test', function() {
beforeEach(module('myApp.view1'));
it('should correclty execute a Promise.then', function(done) {
inject(function($q) {
var deferred = $q.defer();
deferred.resolve();
deferred.promise.then(function() {
console.log('executing Promise.then');
done();
});
});
});
});
EOF
karma start
Karma fails with:
The problem seems to be that the $browser.defer.flush()
gets never called in this scenario.
Interim fix — add this to the app/view1/view1.js (ideally put it in a file only Karma can see):
.config(function($provide) {
$provide.decorator('$browser', function($delegate) {
$delegate.defer = function(fn, delay) {
setTimeout(fn, delay || 0);
};
return $delegate;
});
})
The fix makes Karma work again:
No idea how this should be fixed proper, so not submitting a PR.
You need to call $rootScope.$digest() for promises to get resolved. Please keep in mind that this is not a support forum, please use StackOverflow to get support.
Hi @lgalfaso and thanks for the resolution. I of course went to great lengths to find the solution first, both on Google and StackOverflow. So hopefully this page will index differently and save other people the work and time.
As for the technical aspect, calling $rootScope.$digest()
is limited to 10 iterations of immediate (synchronous) Promise executions, and doesn't work if there's more Promises scheduled asynchronously. Please consider the following test, where the second Promise.then
won't get executed:
'use strict';
describe('Promise test', function() {
beforeEach(module('myApp.view1'));
it('should correclty execute a Promise.then', function(done) {
inject(function($q, $rootScope) {
var deferred = $q.defer();
deferred.resolve();
deferred.promise.then(function() {
console.log('executing Promise.then 1');
// this could be a new Promise scheduled by a 3rd party library function,
// i.e. not possible to call another `$rootScope.$digest();` in between.
setTimeout(function() {
var deferred2 = $q.defer();
deferred.promise.then(function() {
console.log('executing Promise.then 2');
done();
});
}, 500);
});
$rootScope.$digest();
});
});
});
Would this be something Angular devs would consider as a possible room for improvement?
In a test, you have to be in absolute control of when are things executed. This is why there are services like $timeout
(and their ng-mock versions).
@youurayy did you ever find a good solution to this? I'm dealing with the same issue now and can find no solutions anywhere other than overriding $q
with Q
which I would rather not do.
@grahamj i have not
Most helpful comment
Hi @lgalfaso and thanks for the resolution. I of course went to great lengths to find the solution first, both on Google and StackOverflow. So hopefully this page will index differently and save other people the work and time.
As for the technical aspect, calling
$rootScope.$digest()
is limited to 10 iterations of immediate (synchronous) Promise executions, and doesn't work if there's more Promises scheduled asynchronously. Please consider the following test, where the secondPromise.then
won't get executed:Would this be something Angular devs would consider as a possible room for improvement?