Skip to content

Commit 2de6cd0

Browse files
committed
Get rid of implicit digest() (see #41)
Instead wrap each promise object so the resolved value or error is exposed on the promise
1 parent 133e17f commit 2de6cd0

File tree

2 files changed

+66
-21
lines changed

2 files changed

+66
-21
lines changed

test/stateSpec.js

+13-9
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,40 @@ describe('state', function () {
1717
expect($state.$current).toBeDefined();
1818
}));
1919

20-
it('.$current wraps the raw state object', inject(function ($state) {
21-
resolvedValue($state.transitionTo(A, {}));
20+
it('.$current wraps the raw state object', inject(function ($state, $q) {
21+
$state.transitionTo(A, {});
22+
$q.flush();
2223
expect($state.$current.data).toBe(A.data); // 'data' is reserved for app use
2324
}));
2425

25-
it('.transitionTo() returns a promise for the target state', inject(function ($state) {
26+
it('.transitionTo() returns a promise for the target state', inject(function ($state, $q) {
2627
var trans = $state.transitionTo(A, {});
28+
$q.flush();
2729
expect(resolvedValue(trans)).toBe(A);
2830
}));
2931

30-
it('.current updates asynchronously as the transitionTo() promise is resolved', inject(function ($state) {
32+
it('.current updates asynchronously as the transitionTo() promise is resolved', inject(function ($state, $q) {
3133
var trans = $state.transitionTo(A, {});
3234
expect($state.current).not.toBe(A);
33-
resolvedValue(trans);
35+
$q.flush();
3436
expect($state.current).toBe(A);
3537
}));
3638

37-
it('.$transition is always the current or last transition', inject(function ($state) {
39+
it('.$transition is always the current or last transition', inject(function ($state, $q) {
3840
expect($state.$transition).toBeDefined();
41+
$q.flush();
3942
expect(resolvedValue($state.$transition)).toBe($state.current);
4043
var trans = $state.transitionTo(A, {});
4144
expect($state.$transition).toBeDefined();
4245
expect($state.$transition).toBe(trans);
43-
resolvedValue(trans);
46+
$q.flush();
4447
expect($state.$transition).toBe(trans);
4548
}));
4649

47-
it('.transition is null when no transition is taking place', inject(function ($state) {
50+
it('.transition is null when no transition is taking place', inject(function ($state, $q) {
4851
expect($state.transition).toBeNull();
49-
resolvedValue($state.transitionTo(A, {}));
52+
$state.transitionTo(A, {});
53+
$q.flush();
5054
expect($state.transition).toBeNull();
5155
}));
5256
});

test/testUtils.js

+53-12
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,67 @@
1-
function resolvePromise(promise) {
2-
if (!promise.then) throw new Error('Expected a promise, but got ' + jasmine.pp(promise) + '.');
3-
4-
var result;
5-
promise.then(function (value) {
6-
result = { success: true, value: value };
7-
}, function (error) {
8-
result = { success: false, error: error };
1+
angular.module('ngMock')
2+
.config(function ($provide) {
3+
$provide.decorator('$q', function ($delegate, $rootScope) {
4+
$delegate.flush = function() {
5+
$rootScope.$digest();
6+
};
7+
8+
// Add callbacks to the promise that expose the resolved value/error
9+
function expose(promise) {
10+
// Don't add hooks to the same promise twice (shouldn't happen anyway)
11+
if (!promise.hasOwnProperty('$$resolved')) {
12+
promise.$$resolved = false;
13+
promise.then(function (value) {
14+
promise.$$resolved = { success: true, value: value };
15+
}, function (error) {
16+
promise.$$resolved = { success: false, error: error };
17+
});
18+
19+
// We need to expose() any then()ed promises recursively
20+
var qThen = promise.then;
21+
promise.then = function () {
22+
return expose(qThen.apply(this, arguments));
23+
};
24+
}
25+
return promise;
26+
}
27+
28+
// Wrap functions that return a promise
29+
angular.forEach([ 'when', 'all', 'reject'], function (name) {
30+
var qFunc = $delegate[name];
31+
$delegate[name] = function () {
32+
return expose(qFunc.apply(this, arguments));
33+
};
34+
});
35+
36+
// Wrap defer()
37+
var qDefer = $delegate.defer;
38+
$delegate.defer = function () {
39+
var deferred = qDefer();
40+
expose(deferred.promise);
41+
return deferred;
42+
}
43+
44+
return $delegate;
45+
});
946
});
1047

11-
jasmine.getEnv().currentSpec.$injector.get('$rootScope').$digest();
12-
if (!result) throw new Error('Promise is still pending');
48+
49+
function resolvedPromise(promise) {
50+
if (!promise.then) throw new Error('Expected a promise, but got ' + jasmine.pp(promise) + '.');
51+
var result = promise.$$resolved;
52+
if (!isDefined(result)) throw new Error('Promise has not been augmented by ngMock');
53+
if (!result) throw new Error('Promise is not resolved yet');
1354
return result;
1455
}
1556

1657
function resolvedValue(promise) {
17-
var result = resolvePromise(promise);
58+
var result = resolvedPromise(promise);
1859
if (!result.success) throw result.error;
1960
return result.value;
2061
}
2162

2263
function resolvedError(promise) {
23-
var result = resolvePromise(promise);
64+
var result = resolvedPromise(promise);
2465
if (result.success) throw new Error('Promise was expected to fail but returned ' + jasmin.pp(res.value) + '.');
2566
return result.error;
2667
}

0 commit comments

Comments
 (0)