Commit 5812fc46 authored by Nick Stenning's avatar Nick Stenning

Don't mix-and-match Angular and native Promises

Well this was fun to debug.

Not.

So, it seems that in 1.4 (as opposed to 1.2) Angular Promises are
special, and don't play well with native browser Promises. In
particular, Angular promises don't resolve until a digest cycle, which
means that while this test will pass:

    it('should resolve', function (done) {
       var resolved = false;

       $timeout(function () { resolved = true; });
       .then(function () {
         assert.isTrue(resolved);
       })
       .then(done, done);

       $timeout.flush(); // <- this triggers a digest cycle
    });

This one will not -- Mocha will time it out, because the digest cycle
triggered by `$timeout.flush()` occurs before the fulfillment handlers
(with the assertions and the call to `done`) are registered:

    it('should resolve', function (done) {
       var resolved = false;
       var wait = $timeout(function () { resolved = true; });

       $timeout.flush();

       wait.then(function () {
         assert.isTrue(resolved);
       })
       .then(done, done);
    });

If that were the whole story, I would be merely mildly displeased. But
it's not...

The return value of a call to `.then(onFulfilled, onRejected)` is a
promise of the return value of the `onFulfilled` callback, which is what
makes Promises chainable. If `onFulfilled` returns a promise, then that
is (or should be) the promise returned by `.then(...)`. Unfortunately,
if we actually do this:

    it('should resolve', function (done) {
       $timeout(function () {
          return Promise.resolve('abc');
       })
       .then(function (val) {
         assert.equal(val, 'abc');
       })
       .then(done, done);

       $timeout.flush(); // <- this triggers a digest cycle
    });

Then again, Mocha will time out on this test. This is probably because
the returned Promise resolves on runtime `nextTick`, which is *after*
the call to `$timeout.flush()`, which means it's after the relevant part
of the digest cycle which processes the fulfillment handlers for the
Angular-style promise.

ARGH, Angular. Argh.
parent f2c25e3b
......@@ -4,6 +4,7 @@ describe 'annotation', ->
$compile = null
$document = null
$element = null
$q = null
$rootScope = null
$scope = null
$timeout = null
......@@ -111,9 +112,10 @@ describe 'annotation', ->
$provide.value 'groups', fakeGroups
return
beforeEach inject (_$compile_, _$document_, _$rootScope_, _$timeout_) ->
beforeEach inject (_$compile_, _$document_, _$q_, _$rootScope_, _$timeout_) ->
$compile = _$compile_
$document = _$document_
$q = _$q_
$timeout = _$timeout_
$rootScope = _$rootScope_
$scope = $rootScope.$new()
......@@ -463,7 +465,7 @@ describe 'annotation', ->
it "calls annotationMapper.delete() if the delete is confirmed", (done) ->
window.confirm.returns(true)
fakeAnnotationMapper.deleteAnnotation.returns(Promise.resolve())
fakeAnnotationMapper.deleteAnnotation.returns($q.resolve())
controller.delete().then ->
assert fakeAnnotationMapper.deleteAnnotation.calledWith(annotation)
......@@ -476,7 +478,7 @@ describe 'annotation', ->
it "flashes a generic error if the server cannot be reached", (done) ->
window.confirm.returns(true)
fakeAnnotationMapper.deleteAnnotation.returns(Promise.reject({status: 0}))
fakeAnnotationMapper.deleteAnnotation.returns($q.reject({status: 0}))
controller.delete().then ->
assert fakeFlash.error.calledWith(
......@@ -486,7 +488,7 @@ describe 'annotation', ->
it "flashes an error if the delete fails on the server", (done) ->
window.confirm.returns(true)
fakeAnnotationMapper.deleteAnnotation.returns(Promise.reject({
fakeAnnotationMapper.deleteAnnotation.returns($q.reject({
status: 500,
statusText: "Server Error",
data: {}
......@@ -501,7 +503,7 @@ describe 'annotation', ->
it "doesn't flash an error if the delete succeeds", (done) ->
window.confirm.returns(true)
fakeAnnotationMapper.deleteAnnotation.returns(Promise.resolve())
fakeAnnotationMapper.deleteAnnotation.returns($q.resolve())
controller.delete().then ->
assert fakeFlash.error.notCalled
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment