@@ -34,6 +34,7 @@ import * as reload from '../user/reload';
34
34
import { AuthImpl , DefaultConfig } from './auth_impl' ;
35
35
import { _initializeAuthInstance } from './initialize' ;
36
36
import { ClientPlatform } from '../util/version' ;
37
+ import { AuthErrorCode } from '../errors' ;
37
38
38
39
use ( sinonChai ) ;
39
40
use ( chaiAsPromised ) ;
@@ -138,6 +139,11 @@ describe('core/auth/auth_impl', () => {
138
139
expect ( persistenceStub . _remove ) . to . have . been . called ;
139
140
expect ( auth . currentUser ) . to . be . null ;
140
141
} ) ;
142
+ it ( 'is blocked if a beforeAuthStateChanged callback throws' , async ( ) => {
143
+ await auth . _updateCurrentUser ( testUser ( auth , 'test' ) ) ;
144
+ auth . beforeAuthStateChanged ( sinon . stub ( ) . throws ( ) ) ;
145
+ await expect ( auth . signOut ( ) ) . to . be . rejectedWith ( AuthErrorCode . LOGIN_BLOCKED ) ;
146
+ } ) ;
141
147
} ) ;
142
148
143
149
describe ( '#useDeviceLanguage' , ( ) => {
@@ -208,20 +214,24 @@ describe('core/auth/auth_impl', () => {
208
214
let user : UserInternal ;
209
215
let authStateCallback : sinon . SinonSpy ;
210
216
let idTokenCallback : sinon . SinonSpy ;
217
+ let beforeAuthCallback : sinon . SinonSpy ;
211
218
212
219
beforeEach ( ( ) => {
213
220
user = testUser ( auth , 'uid' ) ;
214
221
authStateCallback = sinon . spy ( ) ;
215
222
idTokenCallback = sinon . spy ( ) ;
223
+ beforeAuthCallback = sinon . spy ( ) ;
216
224
} ) ;
217
225
218
226
context ( 'initially currentUser is null' , ( ) => {
219
227
beforeEach ( async ( ) => {
220
228
auth . onAuthStateChanged ( authStateCallback ) ;
221
229
auth . onIdTokenChanged ( idTokenCallback ) ;
230
+ auth . beforeAuthStateChanged ( beforeAuthCallback ) ;
222
231
await auth . _updateCurrentUser ( null ) ;
223
232
authStateCallback . resetHistory ( ) ;
224
233
idTokenCallback . resetHistory ( ) ;
234
+ beforeAuthCallback . resetHistory ( ) ;
225
235
} ) ;
226
236
227
237
it ( 'onAuthStateChange triggers on log in' , async ( ) => {
@@ -233,15 +243,22 @@ describe('core/auth/auth_impl', () => {
233
243
await auth . _updateCurrentUser ( user ) ;
234
244
expect ( idTokenCallback ) . to . have . been . calledWith ( user ) ;
235
245
} ) ;
246
+
247
+ it ( 'beforeAuthStateChanged triggers on log in' , async ( ) => {
248
+ await auth . _updateCurrentUser ( user ) ;
249
+ expect ( beforeAuthCallback ) . to . have . been . calledWith ( user ) ;
250
+ } ) ;
236
251
} ) ;
237
252
238
253
context ( 'initially currentUser is user' , ( ) => {
239
254
beforeEach ( async ( ) => {
240
255
auth . onAuthStateChanged ( authStateCallback ) ;
241
256
auth . onIdTokenChanged ( idTokenCallback ) ;
257
+ auth . beforeAuthStateChanged ( beforeAuthCallback ) ;
242
258
await auth . _updateCurrentUser ( user ) ;
243
259
authStateCallback . resetHistory ( ) ;
244
260
idTokenCallback . resetHistory ( ) ;
261
+ beforeAuthCallback . resetHistory ( ) ;
245
262
} ) ;
246
263
247
264
it ( 'onAuthStateChange triggers on log out' , async ( ) => {
@@ -254,6 +271,11 @@ describe('core/auth/auth_impl', () => {
254
271
expect ( idTokenCallback ) . to . have . been . calledWith ( null ) ;
255
272
} ) ;
256
273
274
+ it ( 'beforeAuthStateChanged triggers on log out' , async ( ) => {
275
+ await auth . _updateCurrentUser ( null ) ;
276
+ expect ( beforeAuthCallback ) . to . have . been . calledWith ( null ) ;
277
+ } ) ;
278
+
257
279
it ( 'onAuthStateChange does not trigger for user props change' , async ( ) => {
258
280
user . photoURL = 'blah' ;
259
281
await auth . _updateCurrentUser ( user ) ;
@@ -300,21 +322,61 @@ describe('core/auth/auth_impl', () => {
300
322
expect ( cb1 ) . to . have . been . calledWith ( user ) ;
301
323
expect ( cb2 ) . to . have . been . calledWith ( user ) ;
302
324
} ) ;
325
+
326
+ it ( 'beforeAuthStateChange works for multiple listeners' , async ( ) => {
327
+ const cb1 = sinon . spy ( ) ;
328
+ const cb2 = sinon . spy ( ) ;
329
+ auth . beforeAuthStateChanged ( cb1 ) ;
330
+ auth . beforeAuthStateChanged ( cb2 ) ;
331
+ await auth . _updateCurrentUser ( null ) ;
332
+ cb1 . resetHistory ( ) ;
333
+ cb2 . resetHistory ( ) ;
334
+
335
+ await auth . _updateCurrentUser ( user ) ;
336
+ expect ( cb1 ) . to . have . been . calledWith ( user ) ;
337
+ expect ( cb2 ) . to . have . been . calledWith ( user ) ;
338
+ } ) ;
339
+
340
+ it ( '_updateCurrentUser throws if a beforeAuthStateChange callback throws' , async ( ) => {
341
+ await auth . _updateCurrentUser ( null ) ;
342
+ const cb1 = sinon . stub ( ) . throws ( ) ;
343
+ const cb2 = sinon . spy ( ) ;
344
+ auth . beforeAuthStateChanged ( cb1 ) ;
345
+ auth . beforeAuthStateChanged ( cb2 ) ;
346
+
347
+ await expect ( auth . _updateCurrentUser ( user ) ) . to . be . rejectedWith ( AuthErrorCode . LOGIN_BLOCKED ) ;
348
+ expect ( cb2 ) . not . to . be . called ;
349
+ } ) ;
350
+
351
+ it ( '_updateCurrentUser throws if a beforeAuthStateChange callback rejects' , async ( ) => {
352
+ await auth . _updateCurrentUser ( null ) ;
353
+ const cb1 = sinon . stub ( ) . rejects ( ) ;
354
+ const cb2 = sinon . spy ( ) ;
355
+ auth . beforeAuthStateChanged ( cb1 ) ;
356
+ auth . beforeAuthStateChanged ( cb2 ) ;
357
+
358
+ await expect ( auth . _updateCurrentUser ( user ) ) . to . be . rejectedWith ( AuthErrorCode . LOGIN_BLOCKED ) ;
359
+ expect ( cb2 ) . not . to . be . called ;
360
+ } ) ;
303
361
} ) ;
304
362
} ) ;
305
363
306
364
describe ( '#_onStorageEvent' , ( ) => {
307
365
let authStateCallback : sinon . SinonSpy ;
308
366
let idTokenCallback : sinon . SinonSpy ;
367
+ let beforeStateCallback : sinon . SinonSpy ;
309
368
310
369
beforeEach ( async ( ) => {
311
370
authStateCallback = sinon . spy ( ) ;
312
371
idTokenCallback = sinon . spy ( ) ;
372
+ beforeStateCallback = sinon . spy ( ) ;
313
373
auth . onAuthStateChanged ( authStateCallback ) ;
314
374
auth . onIdTokenChanged ( idTokenCallback ) ;
375
+ auth . beforeAuthStateChanged ( beforeStateCallback ) ;
315
376
await auth . _updateCurrentUser ( null ) ; // force event handlers to clear out
316
377
authStateCallback . resetHistory ( ) ;
317
378
idTokenCallback . resetHistory ( ) ;
379
+ beforeStateCallback . resetHistory ( ) ;
318
380
} ) ;
319
381
320
382
context ( 'previously logged out' , ( ) => {
@@ -324,6 +386,7 @@ describe('core/auth/auth_impl', () => {
324
386
325
387
expect ( authStateCallback ) . not . to . have . been . called ;
326
388
expect ( idTokenCallback ) . not . to . have . been . called ;
389
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
327
390
} ) ;
328
391
} ) ;
329
392
@@ -341,6 +404,8 @@ describe('core/auth/auth_impl', () => {
341
404
expect ( auth . currentUser ?. toJSON ( ) ) . to . eql ( user . toJSON ( ) ) ;
342
405
expect ( authStateCallback ) . to . have . been . called ;
343
406
expect ( idTokenCallback ) . to . have . been . called ;
407
+ // This should never be called on a storage event.
408
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
344
409
} ) ;
345
410
} ) ;
346
411
} ) ;
@@ -353,6 +418,7 @@ describe('core/auth/auth_impl', () => {
353
418
await auth . _updateCurrentUser ( user ) ;
354
419
authStateCallback . resetHistory ( ) ;
355
420
idTokenCallback . resetHistory ( ) ;
421
+ beforeStateCallback . resetHistory ( ) ;
356
422
} ) ;
357
423
358
424
context ( 'now logged out' , ( ) => {
@@ -366,6 +432,8 @@ describe('core/auth/auth_impl', () => {
366
432
expect ( auth . currentUser ) . to . be . null ;
367
433
expect ( authStateCallback ) . to . have . been . called ;
368
434
expect ( idTokenCallback ) . to . have . been . called ;
435
+ // This should never be called on a storage event.
436
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
369
437
} ) ;
370
438
} ) ;
371
439
@@ -378,6 +446,7 @@ describe('core/auth/auth_impl', () => {
378
446
expect ( auth . currentUser ?. toJSON ( ) ) . to . eql ( user . toJSON ( ) ) ;
379
447
expect ( authStateCallback ) . not . to . have . been . called ;
380
448
expect ( idTokenCallback ) . not . to . have . been . called ;
449
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
381
450
} ) ;
382
451
383
452
it ( 'should update fields if they have changed' , async ( ) => {
@@ -391,6 +460,7 @@ describe('core/auth/auth_impl', () => {
391
460
expect ( auth . currentUser ?. displayName ) . to . eq ( 'other-name' ) ;
392
461
expect ( authStateCallback ) . not . to . have . been . called ;
393
462
expect ( idTokenCallback ) . not . to . have . been . called ;
463
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
394
464
} ) ;
395
465
396
466
it ( 'should update tokens if they have changed' , async ( ) => {
@@ -407,6 +477,8 @@ describe('core/auth/auth_impl', () => {
407
477
) . to . eq ( 'new-access-token' ) ;
408
478
expect ( authStateCallback ) . not . to . have . been . called ;
409
479
expect ( idTokenCallback ) . to . have . been . called ;
480
+ // This should never be called on a storage event.
481
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
410
482
} ) ;
411
483
} ) ;
412
484
@@ -420,6 +492,8 @@ describe('core/auth/auth_impl', () => {
420
492
expect ( auth . currentUser ?. toJSON ( ) ) . to . eql ( newUser . toJSON ( ) ) ;
421
493
expect ( authStateCallback ) . to . have . been . called ;
422
494
expect ( idTokenCallback ) . to . have . been . called ;
495
+ // This should never be called on a storage event.
496
+ expect ( beforeStateCallback ) . not . to . have . been . called ;
423
497
} ) ;
424
498
} ) ;
425
499
} ) ;
@@ -461,7 +535,7 @@ describe('core/auth/auth_impl', () => {
461
535
} ) ;
462
536
} ) ;
463
537
464
- context ( '#_getAdditionalHeaders' , ( ) => {
538
+ context ( '#_getAdditionalHeaders' , ( ) => {
465
539
it ( 'always adds the client version' , async ( ) => {
466
540
expect ( await auth . _getAdditionalHeaders ( ) ) . to . eql ( {
467
541
'X-Client-Version' : 'v' ,
0 commit comments