@@ -24,6 +24,7 @@ import { FirebaseError } from '@firebase/util';
24
24
25
25
import { testUser } from '../../../test/mock_auth' ;
26
26
import { Auth } from '../../model/auth' ;
27
+ import { User } from '../../model/user' ;
27
28
import { Persistence } from '../persistence' ;
28
29
import { browserLocalPersistence } from '../persistence/browser' ;
29
30
import { inMemoryPersistence } from '../persistence/in_memory' ;
@@ -117,6 +118,139 @@ describe('AuthImpl', () => {
117
118
) ;
118
119
} ) ;
119
120
} ) ;
121
+
122
+ describe ( 'change listeners' , ( ) => {
123
+ // // Helpers to convert auth state change results to promise
124
+ // function onAuthStateChange(callback: NextFn<User|null>)
125
+
126
+ it ( 'immediately calls authStateChange if initialization finished' , done => {
127
+ const user = testUser ( 'uid' ) ;
128
+ auth . currentUser = user ;
129
+ auth . _isInitialized = true ;
130
+ auth . onAuthStateChanged ( user => {
131
+ expect ( user ) . to . eq ( user ) ;
132
+ done ( ) ;
133
+ } ) ;
134
+ } ) ;
135
+
136
+ it ( 'immediately calls idTokenChange if initialization finished' , done => {
137
+ const user = testUser ( 'uid' ) ;
138
+ auth . currentUser = user ;
139
+ auth . _isInitialized = true ;
140
+ auth . onIdTokenChange ( user => {
141
+ expect ( user ) . to . eq ( user ) ;
142
+ done ( ) ;
143
+ } ) ;
144
+ } ) ;
145
+
146
+ it ( 'immediate callback is done async' , ( ) => {
147
+ auth . _isInitialized = true ;
148
+ let callbackCalled = false ;
149
+ auth . onIdTokenChange ( ( ) => {
150
+ callbackCalled = true ;
151
+ } ) ;
152
+
153
+ expect ( callbackCalled ) . to . be . false ;
154
+ } ) ;
155
+
156
+ describe ( 'user logs in/out, tokens refresh' , ( ) => {
157
+ let user : User ;
158
+ let authStateCallback : sinon . SinonSpy ;
159
+ let idTokenCallback : sinon . SinonSpy ;
160
+
161
+ beforeEach ( ( ) => {
162
+ user = testUser ( 'uid' ) ;
163
+ authStateCallback = sinon . spy ( ) ;
164
+ idTokenCallback = sinon . spy ( ) ;
165
+ } ) ;
166
+
167
+ context ( 'initially currentUser is null' , ( ) => {
168
+ beforeEach ( async ( ) => {
169
+ auth . onAuthStateChanged ( authStateCallback ) ;
170
+ auth . onIdTokenChange ( idTokenCallback ) ;
171
+ await auth . updateCurrentUser ( null ) ;
172
+ authStateCallback . resetHistory ( ) ;
173
+ idTokenCallback . resetHistory ( ) ;
174
+ } ) ;
175
+
176
+ it ( 'onAuthStateChange triggers on log in' , async ( ) => {
177
+ await auth . updateCurrentUser ( user ) ;
178
+ expect ( authStateCallback ) . to . have . been . calledWith ( user ) ;
179
+ } ) ;
180
+
181
+ it ( 'onIdTokenChange triggers on log in' , async ( ) => {
182
+ await auth . updateCurrentUser ( user ) ;
183
+ expect ( idTokenCallback ) . to . have . been . calledWith ( user ) ;
184
+ } ) ;
185
+ } ) ;
186
+
187
+ context ( 'initially currentUser is user' , ( ) => {
188
+ beforeEach ( async ( ) => {
189
+ auth . onAuthStateChanged ( authStateCallback ) ;
190
+ auth . onIdTokenChange ( idTokenCallback ) ;
191
+ await auth . updateCurrentUser ( user ) ;
192
+ authStateCallback . resetHistory ( ) ;
193
+ idTokenCallback . resetHistory ( ) ;
194
+ } ) ;
195
+
196
+ it ( 'onAuthStateChange triggers on log out' , async ( ) => {
197
+ await auth . updateCurrentUser ( null ) ;
198
+ expect ( authStateCallback ) . to . have . been . calledWith ( null ) ;
199
+ } ) ;
200
+
201
+ it ( 'onIdTokenChange triggers on log out' , async ( ) => {
202
+ await auth . updateCurrentUser ( null ) ;
203
+ expect ( idTokenCallback ) . to . have . been . calledWith ( null ) ;
204
+ } ) ;
205
+
206
+ it ( 'onAuthStateChange does not trigger for user props change' , async ( ) => {
207
+ user . refreshToken = 'hey look I changed' ;
208
+ await auth . updateCurrentUser ( user ) ;
209
+ expect ( authStateCallback ) . not . to . have . been . called ;
210
+ } ) ;
211
+
212
+ it ( 'onIdTokenChange triggers for user props change' , async ( ) => {
213
+ user . refreshToken = 'hey look I changed' ;
214
+ await auth . updateCurrentUser ( user ) ;
215
+ expect ( idTokenCallback ) . to . have . been . calledWith ( user ) ;
216
+ } ) ;
217
+
218
+ it ( 'onAuthStateChange triggers if uid changes' , async ( ) => {
219
+ const newUser = testUser ( 'different-uid' ) ;
220
+ await auth . updateCurrentUser ( newUser ) ;
221
+ expect ( authStateCallback ) . to . have . been . calledWith ( newUser ) ;
222
+ } ) ;
223
+ } ) ;
224
+
225
+ it ( 'onAuthStateChange works for multiple listeners' , async ( ) => {
226
+ const cb1 = sinon . spy ( ) ;
227
+ const cb2 = sinon . spy ( ) ;
228
+ auth . onAuthStateChanged ( cb1 ) ;
229
+ auth . onAuthStateChanged ( cb2 ) ;
230
+ await auth . updateCurrentUser ( null ) ;
231
+ cb1 . resetHistory ( ) ;
232
+ cb2 . resetHistory ( ) ;
233
+
234
+ await auth . updateCurrentUser ( user ) ;
235
+ expect ( cb1 ) . to . have . been . calledWith ( user ) ;
236
+ expect ( cb2 ) . to . have . been . calledWith ( user ) ;
237
+ } ) ;
238
+
239
+ it ( 'onIdTokenChange works for multiple listeners' , async ( ) => {
240
+ const cb1 = sinon . spy ( ) ;
241
+ const cb2 = sinon . spy ( ) ;
242
+ auth . onIdTokenChange ( cb1 ) ;
243
+ auth . onIdTokenChange ( cb2 ) ;
244
+ await auth . updateCurrentUser ( null ) ;
245
+ cb1 . resetHistory ( ) ;
246
+ cb2 . resetHistory ( ) ;
247
+
248
+ await auth . updateCurrentUser ( user ) ;
249
+ expect ( cb1 ) . to . have . been . calledWith ( user ) ;
250
+ expect ( cb2 ) . to . have . been . calledWith ( user ) ;
251
+ } ) ;
252
+ } ) ;
253
+ } ) ;
120
254
} ) ;
121
255
122
256
describe ( 'initializeAuth' , ( ) => {
0 commit comments