Skip to content

Commit 911b3ef

Browse files
canacUrigo
authored andcommitted
Support asynchronous validators (#5)
If the validation function passed to $awaitUser returns a promise, the resolved value will be used to determine the user's validity.
1 parent d09fda1 commit 911b3ef

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

src/angular-meteor-auth.js

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ angular.module(name, [
1717
.factory('$$Auth', [
1818
'$Mixer',
1919
'$log',
20+
'$q',
2021

21-
function($Mixer, $log) {
22+
function($Mixer, $log, $q) {
2223
const Accounts = (Package['accounts-base'] || {}).Accounts;
2324

2425
if (!Accounts) {
@@ -77,20 +78,26 @@ function($Mixer, $log) {
7778

7879
if (!this.currentUser) return this.$$afterFlush(deferred.reject, errors.required);
7980

80-
const isValid = validate(this.currentUser);
81-
// Resolve the promise if validation has passed
82-
if (isValid === true) return this.$$afterFlush(deferred.resolve, this.currentUser);
83-
84-
let error;
85-
86-
if (_.isString(isValid) || isValid instanceof Error) {
87-
error = isValid;
88-
}
89-
else {
90-
error = errors.forbidden;
91-
}
92-
93-
return this.$$afterFlush(deferred.reject, error);
81+
$q.when(validate(this.currentUser)).then(isValid => {
82+
// Resolve the promise if validation has passed
83+
if (isValid === true) {
84+
this.$$afterFlush(deferred.resolve, this.currentUser);
85+
}
86+
else {
87+
return $q.reject(isValid);
88+
}
89+
}).catch(isValid => {
90+
let error;
91+
92+
if (_.isString(isValid) || isValid instanceof Error) {
93+
error = isValid;
94+
}
95+
else {
96+
error = errors.forbidden;
97+
}
98+
99+
this.$$afterFlush(deferred.reject, error);
100+
});
94101
});
95102

96103
deferred.promise.stop = computation.stop.bind(computation);

tests/integration/auth.spec.js

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ describe('angular-meteor.auth', function() {
44

55
var Accounts = Package['accounts-base'].Accounts;
66
var $rootScope;
7+
var $q;
78
var $auth;
89

9-
beforeEach(angular.mock.inject(function(_$rootScope_, _$auth_) {
10+
beforeEach(angular.mock.inject(function(_$rootScope_, _$q_, _$auth_) {
1011
$rootScope = _$rootScope_;
12+
$q = _$q_;
1113
$auth = _$auth_;
1214
}));
1315

@@ -175,6 +177,82 @@ describe('angular-meteor.auth', function() {
175177
});
176178
});
177179

180+
it('should succeed if validation method asynchronously returns true', function(done) {
181+
Accounts.login('tempUser', function() {
182+
var spy = jasmine.createSpy().and.returnValue($q.resolve(true));
183+
184+
scope.$awaitUser(spy).then(function() {
185+
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
186+
expect(spy).toHaveBeenCalled();
187+
done();
188+
});
189+
}).onEnd(function() {
190+
scope.$$afterFlush('$$throttledDigest');
191+
});
192+
});
193+
194+
it('should return a custom validation error if validation method asynchronously resolves to a string', function(done) {
195+
Accounts.login('tempUser', function() {
196+
var spy = jasmine.createSpy().and.returnValue($q.resolve('NOT_ALLOWED'));
197+
198+
scope.$awaitUser(spy).catch(function(err) {
199+
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
200+
expect(spy).toHaveBeenCalled();
201+
expect(err).toEqual('NOT_ALLOWED');
202+
done();
203+
});
204+
}).onEnd(function() {
205+
scope.$$afterFlush('$$throttledDigest');
206+
});
207+
});
208+
209+
it('should return a custom validation error if validation method asynchronously resolves to an error', function(done) {
210+
Accounts.login('tempUser', function() {
211+
var err = Error();
212+
var spy = jasmine.createSpy().and.returnValue($q.resolve(err));
213+
214+
scope.$awaitUser(spy).catch(function(err) {
215+
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
216+
expect(spy).toHaveBeenCalled();
217+
expect(err).toEqual(err);
218+
done();
219+
});
220+
}).onEnd(function() {
221+
scope.$$afterFlush('$$throttledDigest');
222+
});
223+
});
224+
225+
it('should return a custom validation error if validation method asynchronously rejects to a string', function(done) {
226+
Accounts.login('tempUser', function() {
227+
var spy = jasmine.createSpy().and.returnValue($q.reject('NOT_ALLOWED'));
228+
229+
scope.$awaitUser(spy).catch(function(err) {
230+
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
231+
expect(spy).toHaveBeenCalled();
232+
expect(err).toEqual('NOT_ALLOWED');
233+
done();
234+
});
235+
}).onEnd(function() {
236+
scope.$$afterFlush('$$throttledDigest');
237+
});
238+
});
239+
240+
it('should return a custom validation error if validation method asynchronously rejects to an error', function(done) {
241+
Accounts.login('tempUser', function() {
242+
var err = Error();
243+
var spy = jasmine.createSpy().and.returnValue($q.reject(err));
244+
245+
scope.$awaitUser(spy).catch(function(err) {
246+
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
247+
expect(spy).toHaveBeenCalled();
248+
expect(err).toEqual(err);
249+
done();
250+
});
251+
}).onEnd(function() {
252+
scope.$$afterFlush('$$throttledDigest');
253+
});
254+
});
255+
178256
it('should not fulfill promise once auto computation has been stopped', function() {
179257
var promise = scope.$awaitUser();
180258
expect(Tracker.Computation.prototype.stop).toHaveBeenCalled();
@@ -301,4 +379,4 @@ describe('angular-meteor.auth', function() {
301379
});
302380
});
303381
});
304-
});
382+
});

0 commit comments

Comments
 (0)