1
1
import { describe , it , expect , vi , beforeEach } from "vitest" ;
2
2
import { FirebaseError } from "firebase/app" ;
3
- import { AuthCredential } from "firebase/auth" ;
3
+ import { Auth , AuthCredential , MultiFactorResolver } from "firebase/auth" ;
4
4
import { FirebaseUIError , handleFirebaseError } from "./errors" ;
5
5
import { createMockUI } from "~/tests/utils" ;
6
6
import { ERROR_CODE_MAP } from "@firebase-ui/translations" ;
7
7
8
- // Mock the translations module
9
8
vi . mock ( "./translations" , ( ) => ( {
10
9
getTranslation : vi . fn ( ) ,
11
10
} ) ) ;
12
11
12
+ vi . mock ( "firebase/auth" , ( ) => ( {
13
+ getMultiFactorResolver : vi . fn ( ) ,
14
+ } ) ) ;
15
+
13
16
import { getTranslation } from "./translations" ;
17
+ import { getMultiFactorResolver } from "firebase/auth" ;
14
18
15
19
let mockSessionStorage : { [ key : string ] : string } ;
16
20
17
21
beforeEach ( ( ) => {
18
22
vi . clearAllMocks ( ) ;
19
23
20
- // Mock sessionStorage
21
24
mockSessionStorage = { } ;
22
25
Object . defineProperty ( window , 'sessionStorage' , {
23
26
value : {
@@ -112,7 +115,6 @@ describe("handleFirebaseError", () => {
112
115
try {
113
116
handleFirebaseError ( mockUI , mockFirebaseError ) ;
114
117
} catch ( error ) {
115
- // Should be an instance of both FirebaseUIError and FirebaseError
116
118
expect ( error ) . toBeInstanceOf ( FirebaseUIError ) ;
117
119
expect ( error ) . toBeInstanceOf ( FirebaseError ) ;
118
120
expect ( ( error as FirebaseUIError ) . code ) . toBe ( "auth/user-not-found" ) ;
@@ -168,17 +170,75 @@ describe("handleFirebaseError", () => {
168
170
vi . mocked ( getTranslation ) . mockReturnValue ( expectedTranslation ) ;
169
171
170
172
expect ( ( ) => handleFirebaseError ( mockUI , mockFirebaseError ) ) . toThrow ( FirebaseUIError ) ;
171
-
172
- // Should not try to store credential if it doesn't exist
173
173
expect ( window . sessionStorage . setItem ) . not . toHaveBeenCalled ( ) ;
174
174
} ) ;
175
+
176
+ it ( "should call setMultiFactorResolver when auth/multi-factor-auth-required error is thrown" , ( ) => {
177
+ const mockUI = createMockUI ( ) ;
178
+ const mockResolver = {
179
+ auth : { } as Auth ,
180
+ session : null ,
181
+ hints : [ ] ,
182
+ } as unknown as MultiFactorResolver ;
183
+
184
+ const error = new FirebaseError ( "auth/multi-factor-auth-required" , "Multi-factor authentication required" ) ;
185
+ const expectedTranslation = "Multi-factor authentication required (translated)" ;
186
+
187
+ vi . mocked ( getTranslation ) . mockReturnValue ( expectedTranslation ) ;
188
+ vi . mocked ( getMultiFactorResolver ) . mockReturnValue ( mockResolver ) ;
189
+
190
+ expect ( ( ) => handleFirebaseError ( mockUI , error ) ) . toThrow ( FirebaseUIError ) ;
191
+ expect ( getMultiFactorResolver ) . toHaveBeenCalledWith ( mockUI . auth , error ) ;
192
+ expect ( mockUI . setMultiFactorResolver ) . toHaveBeenCalledWith ( mockResolver ) ;
193
+ } ) ;
194
+
195
+ it ( "should still throw FirebaseUIError after setting multi-factor resolver" , ( ) => {
196
+ const mockUI = createMockUI ( ) ;
197
+ const mockResolver = {
198
+ auth : { } as Auth ,
199
+ session : null ,
200
+ hints : [ ] ,
201
+ } as unknown as MultiFactorResolver ;
202
+
203
+ const error = new FirebaseError ( "auth/multi-factor-auth-required" , "Multi-factor authentication required" ) ;
204
+ const expectedTranslation = "Multi-factor authentication required (translated)" ;
205
+
206
+ vi . mocked ( getTranslation ) . mockReturnValue ( expectedTranslation ) ;
207
+ vi . mocked ( getMultiFactorResolver ) . mockReturnValue ( mockResolver ) ;
208
+
209
+ expect ( ( ) => handleFirebaseError ( mockUI , error ) ) . toThrow ( FirebaseUIError ) ;
210
+
211
+ expect ( getMultiFactorResolver ) . toHaveBeenCalledWith ( mockUI . auth , error ) ;
212
+ expect ( mockUI . setMultiFactorResolver ) . toHaveBeenCalledWith ( mockResolver ) ;
213
+
214
+ try {
215
+ handleFirebaseError ( mockUI , error ) ;
216
+ } catch ( error ) {
217
+ expect ( error ) . toBeInstanceOf ( FirebaseUIError ) ;
218
+ expect ( error ) . toBeInstanceOf ( FirebaseError ) ;
219
+ expect ( ( error as FirebaseUIError ) . code ) . toBe ( "auth/multi-factor-auth-required" ) ;
220
+ expect ( ( error as FirebaseUIError ) . message ) . toBe ( expectedTranslation ) ;
221
+ }
222
+ } ) ;
223
+
224
+ it ( "should not call setMultiFactorResolver for other error types" , ( ) => {
225
+ const mockUI = createMockUI ( ) ;
226
+ const mockFirebaseError = new FirebaseError ( "auth/user-not-found" , "User not found" ) ;
227
+ const expectedTranslation = "User not found (translated)" ;
228
+
229
+ vi . mocked ( getTranslation ) . mockReturnValue ( expectedTranslation ) ;
230
+
231
+ expect ( ( ) => handleFirebaseError ( mockUI , mockFirebaseError ) ) . toThrow ( FirebaseUIError ) ;
232
+
233
+ expect ( getMultiFactorResolver ) . not . toHaveBeenCalled ( ) ;
234
+ expect ( mockUI . setMultiFactorResolver ) . not . toHaveBeenCalled ( ) ;
235
+ } ) ;
175
236
} ) ;
176
237
177
238
describe ( "isFirebaseError utility" , ( ) => {
178
239
it ( "should identify FirebaseError objects" , ( ) => {
179
240
const firebaseError = new FirebaseError ( "auth/user-not-found" , "User not found" ) ;
180
241
181
- // We can't directly test the private function, but we can test it through handleFirebaseError
182
242
const mockUI = createMockUI ( ) ;
183
243
vi . mocked ( getTranslation ) . mockReturnValue ( "translated message" ) ;
184
244
@@ -187,7 +247,7 @@ describe("isFirebaseError utility", () => {
187
247
188
248
it ( "should reject non-FirebaseError objects" , ( ) => {
189
249
const mockUI = createMockUI ( ) ;
190
- const nonFirebaseError = { code : "test" , message : "test" } ; // Missing proper structure
250
+ const nonFirebaseError = { code : "test" , message : "test" } ;
191
251
192
252
expect ( ( ) => handleFirebaseError ( mockUI , nonFirebaseError ) ) . toThrow ( ) ;
193
253
} ) ;
@@ -218,7 +278,6 @@ describe("errorContainsCredential utility", () => {
218
278
219
279
expect ( ( ) => handleFirebaseError ( mockUI , firebaseErrorWithCredential ) ) . toThrowError ( FirebaseUIError ) ;
220
280
221
- // Should have stored the credential
222
281
expect ( window . sessionStorage . setItem ) . toHaveBeenCalledWith (
223
282
"pendingCred" ,
224
283
JSON . stringify ( mockCredential . toJSON ( ) )
@@ -236,8 +295,6 @@ describe("errorContainsCredential utility", () => {
236
295
237
296
expect ( ( ) => handleFirebaseError ( mockUI , firebaseErrorWithoutCredential ) ) . toThrowError ( FirebaseUIError ) ;
238
297
239
- // Should not have stored any credential
240
298
expect ( window . sessionStorage . setItem ) . not . toHaveBeenCalled ( ) ;
241
299
} ) ;
242
300
} ) ;
243
-
0 commit comments