16
16
17
17
import { describe , it , expect , vi , beforeEach , afterEach } from "vitest" ;
18
18
import { render , screen , fireEvent , renderHook , cleanup } from "@testing-library/react" ;
19
- import { SignUpAuthForm , useSignUpAuthForm , useSignUpAuthFormAction } from "./sign-up-auth-form" ;
19
+ import { SignUpAuthForm , useSignUpAuthForm , useSignUpAuthFormAction , useRequireDisplayName } from "./sign-up-auth-form" ;
20
20
import { act } from "react" ;
21
21
import { createUserWithEmailAndPassword } from "@firebase-ui/core" ;
22
22
import { createFirebaseUIProvider , createMockUI } from "~/tests/utils" ;
@@ -63,7 +63,8 @@ describe("useSignUpAuthFormAction", () => {
63
63
expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
64
64
expect . any ( Object ) ,
65
65
66
- "password123"
66
+ "password123" ,
67
+ undefined
67
68
) ;
68
69
} ) ;
69
70
@@ -88,7 +89,8 @@ describe("useSignUpAuthFormAction", () => {
88
89
expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
89
90
expect . any ( Object ) ,
90
91
91
- "password123"
92
+ "password123" ,
93
+ undefined
92
94
) ;
93
95
} ) ;
94
96
@@ -115,7 +117,35 @@ describe("useSignUpAuthFormAction", () => {
115
117
} ) ;
116
118
} ) . rejects . toThrow ( "unknownError" ) ;
117
119
118
- expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith ( mockUI . get ( ) , "[email protected] " , "password123" ) ;
120
+ expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
121
+ mockUI . get ( ) ,
122
+
123
+ "password123" ,
124
+ undefined
125
+ ) ;
126
+ } ) ;
127
+
128
+ it ( "should return a callback which accepts email, password, and displayName" , async ( ) => {
129
+ const mockCredential = { credential : true } as unknown as UserCredential ;
130
+ const createUserWithEmailAndPasswordMock = vi
131
+ . mocked ( createUserWithEmailAndPassword )
132
+ . mockResolvedValue ( mockCredential ) ;
133
+ const mockUI = createMockUI ( ) ;
134
+
135
+ const { result } = renderHook ( ( ) => useSignUpAuthFormAction ( ) , {
136
+ wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
137
+ } ) ;
138
+
139
+ await act ( async ( ) => {
140
+ await result . current ( { email :
"[email protected] " , password :
"password123" , displayName :
"John Doe" } ) ;
141
+ } ) ;
142
+
143
+ expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
144
+ expect . any ( Object ) ,
145
+
146
+ "password123" ,
147
+ "John Doe"
148
+ ) ;
119
149
} ) ;
120
150
} ) ;
121
151
@@ -129,8 +159,11 @@ describe("useSignUpAuthForm", () => {
129
159
} ) ;
130
160
131
161
it ( "should allow the form to be submitted" , async ( ) => {
162
+ const mockCredential = { credential : true } as unknown as UserCredential ;
132
163
const mockUI = createMockUI ( ) ;
133
- const createUserWithEmailAndPasswordMock = vi . mocked ( createUserWithEmailAndPassword ) ;
164
+ const createUserWithEmailAndPasswordMock = vi
165
+ . mocked ( createUserWithEmailAndPassword )
166
+ . mockResolvedValue ( mockCredential ) ;
134
167
135
168
const { result } = renderHook ( ( ) => useSignUpAuthForm ( ) , {
136
169
wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
@@ -139,13 +172,19 @@ describe("useSignUpAuthForm", () => {
139
172
act ( ( ) => {
140
173
result . current . setFieldValue ( "email" , "[email protected] " ) ;
141
174
result . current . setFieldValue ( "password" , "password123" ) ;
175
+ // Don't set displayName - let it be undefined (optional)
142
176
} ) ;
143
177
144
178
await act ( async ( ) => {
145
179
await result . current . handleSubmit ( ) ;
146
180
} ) ;
147
181
148
- expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith ( mockUI . get ( ) , "[email protected] " , "password123" ) ;
182
+ expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
183
+ mockUI . get ( ) ,
184
+
185
+ "password123" ,
186
+ undefined
187
+ ) ;
149
188
} ) ;
150
189
151
190
it ( "should not allow the form to be submitted if the form is invalid" , async ( ) => {
@@ -167,18 +206,50 @@ describe("useSignUpAuthForm", () => {
167
206
expect ( result . current . getFieldMeta ( "email" ) ! . errors [ 0 ] . length ) . toBeGreaterThan ( 0 ) ;
168
207
expect ( createUserWithEmailAndPasswordMock ) . not . toHaveBeenCalled ( ) ;
169
208
} ) ;
209
+
210
+ it ( "should allow the form to be submitted with displayName" , async ( ) => {
211
+ const mockUI = createMockUI ( ) ;
212
+ const createUserWithEmailAndPasswordMock = vi . mocked ( createUserWithEmailAndPassword ) ;
213
+
214
+ const { result } = renderHook ( ( ) => useSignUpAuthForm ( ) , {
215
+ wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
216
+ } ) ;
217
+
218
+ act ( ( ) => {
219
+ result . current . setFieldValue ( "email" , "[email protected] " ) ;
220
+ result . current . setFieldValue ( "password" , "password123" ) ;
221
+ result . current . setFieldValue ( "displayName" , "John Doe" ) ;
222
+ } ) ;
223
+
224
+ await act ( async ( ) => {
225
+ await result . current . handleSubmit ( ) ;
226
+ } ) ;
227
+
228
+ expect ( createUserWithEmailAndPasswordMock ) . toHaveBeenCalledWith (
229
+ mockUI . get ( ) ,
230
+
231
+ "password123" ,
232
+ "John Doe"
233
+ ) ;
234
+ } ) ;
170
235
} ) ;
171
236
172
237
describe ( "<SignUpAuthForm />" , ( ) => {
173
238
beforeEach ( ( ) => {
174
239
vi . clearAllMocks ( ) ;
175
240
} ) ;
176
241
242
+ afterEach ( ( ) => {
243
+ cleanup ( ) ;
244
+ } ) ;
245
+
177
246
it ( "should render the form correctly" , ( ) => {
178
247
const mockUI = createMockUI ( {
179
248
locale : registerLocale ( "test" , {
180
249
labels : {
181
250
createAccount : "createAccount" ,
251
+ emailAddress : "emailAddress" ,
252
+ password : "password" ,
182
253
} ,
183
254
} ) ,
184
255
} ) ;
@@ -193,9 +264,9 @@ describe("<SignUpAuthForm />", () => {
193
264
const form = container . querySelectorAll ( "form.fui-form" ) ;
194
265
expect ( form . length ) . toBe ( 1 ) ;
195
266
196
- // Make sure we have an email and password input
197
- expect ( screen . getByRole ( "textbox" , { name : / e m a i l / i } ) ) . toBeInTheDocument ( ) ;
198
- expect ( screen . getByRole ( "textbox" , { name : / p a s s w o r d / i } ) ) . toBeInTheDocument ( ) ;
267
+ // Make sure we have an email and password input with translated labels
268
+ expect ( screen . getByRole ( "textbox" , { name : / e m a i l A d d r e s s / } ) ) . toBeInTheDocument ( ) ;
269
+ expect ( screen . getByRole ( "textbox" , { name : / p a s s w o r d / } ) ) . toBeInTheDocument ( ) ;
199
270
200
271
// Ensure the "Create Account" button is present and is a submit button
201
272
const createAccountButton = screen . getByRole ( "button" , { name : "createAccount" } ) ;
@@ -256,4 +327,178 @@ describe("<SignUpAuthForm />", () => {
256
327
257
328
expect ( screen . getByText ( "Please enter a valid email address" ) ) . toBeInTheDocument ( ) ;
258
329
} ) ;
330
+
331
+ it ( "should render displayName field when requireDisplayName behavior is enabled" , ( ) => {
332
+ const mockUI = createMockUI ( {
333
+ locale : registerLocale ( "test" , {
334
+ labels : {
335
+ createAccount : "createAccount" ,
336
+ emailAddress : "emailAddress" ,
337
+ password : "password" ,
338
+ displayName : "displayName" ,
339
+ } ,
340
+ } ) ,
341
+ behaviors : [
342
+ {
343
+ requireDisplayName : { type : "callable" as const , handler : vi . fn ( ) } ,
344
+ } ,
345
+ ] ,
346
+ } ) ;
347
+
348
+ const { container } = render (
349
+ < FirebaseUIProvider ui = { mockUI } >
350
+ < SignUpAuthForm />
351
+ </ FirebaseUIProvider >
352
+ ) ;
353
+
354
+ // There should be only one form
355
+ const form = container . querySelectorAll ( "form.fui-form" ) ;
356
+ expect ( form . length ) . toBe ( 1 ) ;
357
+
358
+ // Make sure we have all three inputs with translated labels
359
+ expect ( screen . getByRole ( "textbox" , { name : / e m a i l A d d r e s s / } ) ) . toBeInTheDocument ( ) ;
360
+ expect ( screen . getByRole ( "textbox" , { name : / p a s s w o r d / } ) ) . toBeInTheDocument ( ) ;
361
+ expect ( screen . getByRole ( "textbox" , { name : / d i s p l a y N a m e / } ) ) . toBeInTheDocument ( ) ;
362
+
363
+ // Ensure the "Create Account" button is present and is a submit button
364
+ const createAccountButton = screen . getByRole ( "button" , { name : "createAccount" } ) ;
365
+ expect ( createAccountButton ) . toBeInTheDocument ( ) ;
366
+ expect ( createAccountButton ) . toHaveAttribute ( "type" , "submit" ) ;
367
+ } ) ;
368
+
369
+ it ( "should not render displayName field when requireDisplayName behavior is not enabled" , ( ) => {
370
+ const mockUI = createMockUI ( {
371
+ locale : registerLocale ( "test" , {
372
+ labels : {
373
+ createAccount : "createAccount" ,
374
+ emailAddress : "emailAddress" ,
375
+ password : "password" ,
376
+ displayName : "displayName" ,
377
+ } ,
378
+ } ) ,
379
+ behaviors : [ ] , // Explicitly set empty behaviors array
380
+ } ) ;
381
+
382
+ const { container } = render (
383
+ < FirebaseUIProvider ui = { mockUI } >
384
+ < SignUpAuthForm />
385
+ </ FirebaseUIProvider >
386
+ ) ;
387
+
388
+ const form = container . querySelectorAll ( "form.fui-form" ) ;
389
+ expect ( form . length ) . toBe ( 1 ) ;
390
+
391
+ expect ( screen . getByRole ( "textbox" , { name : / e m a i l / } ) ) . toBeInTheDocument ( ) ;
392
+ expect ( screen . getByRole ( "textbox" , { name : / p a s s w o r d / } ) ) . toBeInTheDocument ( ) ;
393
+ expect ( screen . queryByRole ( "textbox" , { name : / d i s p l a y N a m e / } ) ) . not . toBeInTheDocument ( ) ;
394
+ } ) ;
395
+
396
+ it ( "should trigger displayName validation errors when the form is blurred and requireDisplayName is enabled" , ( ) => {
397
+ const mockUI = createMockUI ( {
398
+ locale : registerLocale ( "test" , {
399
+ errors : {
400
+ displayNameRequired : "Please provide a display name" ,
401
+ } ,
402
+ labels : {
403
+ displayName : "displayName" ,
404
+ } ,
405
+ } ) ,
406
+ behaviors : [
407
+ {
408
+ requireDisplayName : { type : "callable" as const , handler : vi . fn ( ) } ,
409
+ } ,
410
+ ] ,
411
+ } ) ;
412
+
413
+ const { container } = render (
414
+ < FirebaseUIProvider ui = { mockUI } >
415
+ < SignUpAuthForm />
416
+ </ FirebaseUIProvider >
417
+ ) ;
418
+
419
+ const form = container . querySelector ( "form.fui-form" ) ;
420
+ expect ( form ) . toBeInTheDocument ( ) ;
421
+
422
+ const displayNameInput = screen . getByRole ( "textbox" , { name : / d i s p l a y N a m e / } ) ;
423
+ expect ( displayNameInput ) . toBeInTheDocument ( ) ;
424
+
425
+ act ( ( ) => {
426
+ fireEvent . blur ( displayNameInput ) ;
427
+ } ) ;
428
+
429
+ expect ( screen . getByText ( "Please provide a display name" ) ) . toBeInTheDocument ( ) ;
430
+ } ) ;
431
+
432
+ it ( "should not trigger displayName validation when requireDisplayName is not enabled" , ( ) => {
433
+ const mockUI = createMockUI ( {
434
+ locale : registerLocale ( "test" , {
435
+ errors : {
436
+ displayNameRequired : "Please provide a display name" ,
437
+ } ,
438
+ labels : {
439
+ displayName : "displayName" ,
440
+ } ,
441
+ } ) ,
442
+ } ) ;
443
+
444
+ const { container } = render (
445
+ < FirebaseUIProvider ui = { mockUI } >
446
+ < SignUpAuthForm />
447
+ </ FirebaseUIProvider >
448
+ ) ;
449
+
450
+ const form = container . querySelector ( "form.fui-form" ) ;
451
+ expect ( form ) . toBeInTheDocument ( ) ;
452
+
453
+ // Display name field should not be present
454
+ expect ( screen . queryByRole ( "textbox" , { name : "displayName" } ) ) . not . toBeInTheDocument ( ) ;
455
+ } ) ;
456
+ } ) ;
457
+
458
+ describe ( "useRequireDisplayName" , ( ) => {
459
+ beforeEach ( ( ) => {
460
+ vi . clearAllMocks ( ) ;
461
+ } ) ;
462
+
463
+ afterEach ( ( ) => {
464
+ cleanup ( ) ;
465
+ } ) ;
466
+
467
+ it ( "should return true when requireDisplayName behavior is enabled" , ( ) => {
468
+ const mockUI = createMockUI ( {
469
+ behaviors : [
470
+ {
471
+ requireDisplayName : { type : "callable" as const , handler : vi . fn ( ) } ,
472
+ } ,
473
+ ] ,
474
+ } ) ;
475
+
476
+ const { result } = renderHook ( ( ) => useRequireDisplayName ( ) , {
477
+ wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
478
+ } ) ;
479
+
480
+ expect ( result . current ) . toBe ( true ) ;
481
+ } ) ;
482
+
483
+ it ( "should return false when requireDisplayName behavior is not enabled" , ( ) => {
484
+ const mockUI = createMockUI ( {
485
+ behaviors : [ ] ,
486
+ } ) ;
487
+
488
+ const { result } = renderHook ( ( ) => useRequireDisplayName ( ) , {
489
+ wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
490
+ } ) ;
491
+
492
+ expect ( result . current ) . toBe ( false ) ;
493
+ } ) ;
494
+
495
+ it ( "should return false when behaviors array is empty" , ( ) => {
496
+ const mockUI = createMockUI ( ) ;
497
+
498
+ const { result } = renderHook ( ( ) => useRequireDisplayName ( ) , {
499
+ wrapper : ( { children } ) => createFirebaseUIProvider ( { children, ui : mockUI } ) ,
500
+ } ) ;
501
+
502
+ expect ( result . current ) . toBe ( false ) ;
503
+ } ) ;
259
504
} ) ;
0 commit comments