1+ import { expect , use } from 'chai' ;
2+ import chaiAsPromised from 'chai-as-promised' ;
3+ import * as sinon from 'sinon' ;
4+ import sinonChai from 'sinon-chai' ;
5+ import { testAuth , testUser } from '../../../test/helpers/mock_auth' ;
6+ import { AuthInternal } from '../../model/auth' ;
7+ import { User } from '../../model/public_types' ;
8+ import { AuthMiddlewareQueue } from './middleware' ;
9+
10+ use ( chaiAsPromised ) ;
11+ use ( sinonChai ) ;
12+
13+ describe ( 'Auth middleware' , ( ) => {
14+ let middlewareQueue : AuthMiddlewareQueue ;
15+ let user : User ;
16+ let auth : AuthInternal ;
17+
18+ beforeEach ( async ( ) => {
19+ auth = await testAuth ( ) ;
20+ user = testUser ( auth , 'uid' ) ;
21+ middlewareQueue = new AuthMiddlewareQueue ( auth ) ;
22+ } ) ;
23+
24+ afterEach ( ( ) => {
25+ sinon . restore ( ) ;
26+ } ) ;
27+
28+ it ( 'calls middleware in order' , async ( ) => {
29+ const calls : number [ ] = [ ] ;
30+
31+ middlewareQueue . pushCallback ( ( ) => { calls . push ( 1 ) ; } ) ;
32+ middlewareQueue . pushCallback ( ( ) => { calls . push ( 2 ) ; } ) ;
33+ middlewareQueue . pushCallback ( ( ) => { calls . push ( 3 ) ; } ) ;
34+
35+ await middlewareQueue . runMiddleware ( user ) ;
36+
37+ expect ( calls ) . to . eql ( [ 1 , 2 , 3 ] ) ;
38+ } ) ;
39+
40+ it ( 'rejects on error' , async ( ) => {
41+ middlewareQueue . pushCallback ( ( ) => {
42+ throw new Error ( 'no' ) ;
43+ } ) ;
44+ await expect ( middlewareQueue . runMiddleware ( user ) ) . to . be . rejectedWith ( 'auth/login-blocked' ) ;
45+ } ) ;
46+
47+ it ( 'rejects on promise rejection' , async ( ) => {
48+ middlewareQueue . pushCallback ( ( ) => Promise . reject ( 'no' ) ) ;
49+ await expect ( middlewareQueue . runMiddleware ( user ) ) . to . be . rejectedWith ( 'auth/login-blocked' ) ;
50+ } ) ;
51+
52+ it ( 'awaits middleware completion before calling next' , async ( ) => {
53+ const firstCb = sinon . spy ( ) ;
54+ const secondCb = sinon . spy ( ) ;
55+
56+ middlewareQueue . pushCallback ( ( ) => {
57+ // Force the first one to run one tick later
58+ return new Promise ( resolve => {
59+ setTimeout ( ( ) => {
60+ firstCb ( ) ;
61+ resolve ( ) ;
62+ } , 1 ) ;
63+ } ) ;
64+ } ) ;
65+ middlewareQueue . pushCallback ( secondCb ) ;
66+
67+ await middlewareQueue . runMiddleware ( user ) ;
68+ expect ( secondCb ) . to . have . been . calledAfter ( firstCb ) ;
69+ } ) ;
70+
71+ it ( 'subsequent middleware not run after rejection' , async ( ) => {
72+ const spy = sinon . spy ( ) ;
73+
74+ middlewareQueue . pushCallback ( ( ) => {
75+ throw new Error ( 'no' ) ;
76+ } ) ;
77+ middlewareQueue . pushCallback ( spy ) ;
78+
79+ await expect ( middlewareQueue . runMiddleware ( user ) ) . to . be . rejectedWith ( 'auth/login-blocked' ) ;
80+ expect ( spy ) . not . to . have . been . called ;
81+ } ) ;
82+
83+ it ( 'calls onAbort if provided but only for earlier runs' , async ( ) => {
84+ const firstOnAbort = sinon . spy ( ) ;
85+ const secondOnAbort = sinon . spy ( ) ;
86+
87+ middlewareQueue . pushCallback ( ( ) => { } , firstOnAbort ) ;
88+ middlewareQueue . pushCallback ( ( ) => {
89+ throw new Error ( 'no' ) ;
90+ } , secondOnAbort ) ;
91+
92+ await expect ( middlewareQueue . runMiddleware ( user ) ) . to . be . rejectedWith ( 'auth/login-blocked' ) ;
93+ expect ( firstOnAbort ) . to . have . been . called ;
94+ expect ( secondOnAbort ) . not . to . have . been . called ;
95+ } ) ;
96+
97+ it ( 'calls onAbort in reverse order' , async ( ) => {
98+ const calls : number [ ] = [ ] ;
99+
100+ middlewareQueue . pushCallback ( ( ) => { } , ( ) => { calls . push ( 1 ) ; } ) ;
101+ middlewareQueue . pushCallback ( ( ) => { } , ( ) => { calls . push ( 2 ) ; } ) ;
102+ middlewareQueue . pushCallback ( ( ) => { } , ( ) => { calls . push ( 3 ) ; } ) ;
103+ middlewareQueue . pushCallback ( ( ) => {
104+ throw new Error ( 'no' ) ;
105+ } ) ;
106+
107+ await expect ( middlewareQueue . runMiddleware ( user ) ) . to . be . rejectedWith ( 'auth/login-blocked' ) ;
108+ expect ( calls ) . to . eql ( [ 3 , 2 , 1 ] ) ;
109+ } ) ;
110+
111+ it ( 'does not call any middleware if user matches null' , async ( ) => {
112+ const spy = sinon . spy ( ) ;
113+
114+ middlewareQueue . pushCallback ( spy ) ;
115+ await middlewareQueue . runMiddleware ( null ) ;
116+
117+ expect ( spy ) . not . to . have . been . called ;
118+ } ) ;
119+
120+ it ( 'does not call any middleware if user matches object' , async ( ) => {
121+ const spy = sinon . spy ( ) ;
122+
123+ // Directly set it manually since the public function creates a
124+ // copy of the user.
125+ auth . currentUser = user ;
126+
127+ middlewareQueue . pushCallback ( spy ) ;
128+ await middlewareQueue . runMiddleware ( user ) ;
129+
130+ expect ( spy ) . not . to . have . been . called ;
131+ } ) ;
132+ } ) ;
0 commit comments