@@ -22,12 +22,17 @@ interface FormControlProps extends MockComponentProps {
2222 type ?: string ;
2323 as ?: string ;
2424 controlId ?: string ;
25+ disabled ?: boolean ;
26+ required ?: boolean ;
2527}
2628
2729interface FormCheckProps extends MockComponentProps {
2830 checked ?: boolean ;
2931 label ?: string ;
3032 isInvalid ?: boolean ;
33+ disabled ?: boolean ;
34+ id ?: string ;
35+ type ?: string ;
3136}
3237
3338interface FormFeedbackProps extends MockComponentProps {
@@ -60,6 +65,9 @@ interface AlertProps extends MockComponentProps {
6065
6166interface ButtonProps extends MockComponentProps {
6267 type ?: string ;
68+ variant ?: string ;
69+ disabled ?: boolean ;
70+ onClick ?: ( ) => void ;
6371}
6472
6573// Mock react-bootstrap components with simple HTML elements
@@ -70,6 +78,9 @@ vi.mock('react-bootstrap', () => {
7078 Form . Group = ( { children, controlId, ...props } : MockComponentProps ) => {
7179 if ( children && Array . isArray ( children ) ) {
7280 children = children . map ( ( child ) => {
81+ if ( typeof child !== "object" ) {
82+ return child ;
83+ }
7384 child . props = { ...child . props , controlId } ;
7485 return child ;
7586 } )
@@ -81,14 +92,16 @@ vi.mock('react-bootstrap', () => {
8192 Form . Label = ( { children, controlId, ...props } : MockComponentProps ) =>
8293 h ( 'label' , { ...props , htmlFor : controlId } , children ) ;
8394
84- Form . Control = ( { onChange, value, isInvalid, type, as, controlId, ...props } : FormControlProps ) => {
95+ Form . Control = ( { onChange, value, isInvalid, type, as, controlId, disabled , required , ...props } : FormControlProps ) => {
8596 if ( as === 'textarea' ) {
8697 return h ( 'textarea' , {
8798 ...props ,
8899 role : 'textbox' ,
89100 value,
90101 onChange,
91102 id : controlId ,
103+ disabled,
104+ required,
92105 className : isInvalid ? 'invalid' : '' ,
93106 'data-testid' : `${ type || 'textarea' } -input`
94107 } ) ;
@@ -99,22 +112,30 @@ vi.mock('react-bootstrap', () => {
99112 value,
100113 onChange,
101114 id : controlId ,
115+ disabled,
116+ required,
102117 className : isInvalid ? 'invalid' : '' ,
103118 'data-testid' : `${ type } -input`
104119 } ) ;
105120 } ;
106121
107- Form . Check = ( { checked, label, isInvalid, ...props } : FormCheckProps ) =>
108- h ( 'div' , { } , [
122+ Form . Check = ( { checked, label, isInvalid, disabled , id , type , ...props } : FormCheckProps ) => {
123+ return h ( 'div' , { } , [
109124 h ( 'input' , {
110125 ...props ,
111- type : 'checkbox' ,
126+ type : type || 'checkbox' ,
112127 checked,
128+ disabled,
129+ id,
113130 className : isInvalid ? 'invalid' : '' ,
114131 'data-testid' : 'checkbox'
115132 } ) ,
116- h ( 'label' , { } , label )
133+ h ( 'label' , { htmlFor : id } , label )
117134 ] ) ;
135+ } ;
136+
137+ Form . Text = ( { children, ...props } : MockComponentProps ) =>
138+ h ( 'div' , { ...props , 'data-testid' : 'form-text' } , children ) ;
118139
119140 // eslint-disable-next-line @typescript-eslint/no-explicit-any
120141 ( Form . Control as any ) . Feedback = ( { children, type, ...props } : FormFeedbackProps ) =>
@@ -193,7 +214,14 @@ vi.mock('react-bootstrap', () => {
193214
194215 return {
195216 Alert,
196- Button : ( { children, type, ...props } : ButtonProps ) => h ( 'button' , { ...props , type, 'data-testid' : 'submit-button' } , children ) ,
217+ Button : ( { children, type, variant, disabled, onClick, ...props } : ButtonProps ) => h ( 'button' , {
218+ ...props ,
219+ type,
220+ disabled,
221+ onClick,
222+ className : variant ? `btn btn-${ variant } ` : 'btn' ,
223+ 'data-testid' : 'submit-button'
224+ } , children ) ,
197225 ButtonGroup : ( { children, ...props } : MockComponentProps ) => h ( 'div' , { ...props } , children ) ,
198226 Card,
199227 Col : ( { children, ...props } : MockComponentProps ) => h ( 'div' , { ...props , className : 'col' } , children ) ,
@@ -220,6 +248,7 @@ vi.mock('react-feather', () => ({
220248 ChevronUp : ( ) => h ( 'svg' , { 'data-testid' : 'chevron-up' } ) ,
221249 Edit : ( ) => h ( 'svg' , { 'data-testid' : 'edit-icon' } ) ,
222250 Eye : ( ) => h ( 'svg' , { 'data-testid' : 'eye-icon' } ) ,
251+ EyeOff : ( ) => h ( 'svg' , { 'data-testid' : 'eye-off-icon' } ) ,
223252 Monitor : ( ) => h ( 'svg' , { 'data-testid' : 'monitor-icon' } ) ,
224253 Trash2 : ( ) => h ( 'svg' , { 'data-testid' : 'trash-icon' , className : 'feather-trash-2' } ) ,
225254} ) ) ;
@@ -247,6 +276,7 @@ vi.mock('libsodium-wrappers', () => ({
247276 crypto_box_seal : vi . fn ( ) ,
248277 crypto_box_keypair : vi . fn ( ) ,
249278 crypto_secretbox_easy : vi . fn ( ) ,
279+ crypto_secretbox_open_easy : vi . fn ( ) ,
250280 crypto_secretbox_NONCEBYTES : 24 ,
251281 crypto_secretbox_KEYBYTES : 32 ,
252282 } ,
@@ -266,19 +296,27 @@ vi.mock('js-base64', () => ({
266296} ) ) ;
267297
268298// Mock utils
269- vi . mock ( '.. /utils' , ( ) => ( {
299+ vi . mock ( './utils' , ( ) => ( {
270300 fetchClient : {
271301 GET : vi . fn ( ) ,
272302 POST : vi . fn ( ) ,
303+ PUT : vi . fn ( ) ,
273304 DELETE : vi . fn ( ) ,
274305 } ,
275306 get_decrypted_secret : vi . fn ( ) ,
276307 pub_key : new Uint8Array ( ) ,
277308 secret : new Uint8Array ( ) ,
309+ PASSWORD_PATTERN : / (? = .* \d ) (? = .* [ a - z ] ) (? = .* [ A - Z ] ) .{ 8 , } / ,
310+ generate_hash : vi . fn ( ) ,
311+ generate_random_bytes : vi . fn ( ) ,
312+ get_salt : vi . fn ( ) ,
313+ get_salt_for_user : vi . fn ( ) ,
314+ concat_salts : vi . fn ( ) ,
315+ isDebugMode : { value : false } ,
278316} ) ) ;
279317
280318// Mock Alert component
281- vi . mock ( '.. /components/Alert' , ( ) => ( {
319+ vi . mock ( './components/Alert' , ( ) => ( {
282320 showAlert : vi . fn ( ) ,
283321} ) ) ;
284322
@@ -314,10 +352,71 @@ vi.mock('./i18n', () => ({
314352} ) ) ;
315353
316354// Mock Circle component
317- vi . mock ( '.. /components/Circle' , ( ) => ( {
355+ vi . mock ( './components/Circle' , ( ) => ( {
318356 Circle : vi . fn ( ( ) => null ) ,
319357} ) ) ;
320358
359+ // Mock Navbar component
360+ vi . mock ( './components/Navbar' , ( ) => ( {
361+ logout : vi . fn ( ) ,
362+ } ) ) ;
363+
364+ // Mock PasswordComponent
365+ vi . mock ( './components/PasswordComponent' , ( ) => ( {
366+ PasswordComponent : ( { onChange, isInvalid, invalidMessage, controlId } : {
367+ onChange : ( value : string ) => void ;
368+ isInvalid : boolean ;
369+ invalidMessage : string ;
370+ controlId : string ;
371+ } ) => {
372+ return h ( 'div' , { } , [
373+ h ( 'input' , {
374+ type : 'textbox' ,
375+ 'data-testid' : 'password-input' ,
376+ onChange : ( e : Event ) => onChange ( ( e . target as HTMLInputElement ) . value ) ,
377+ id : controlId ,
378+ className : isInvalid ? 'invalid' : '' ,
379+ } ) ,
380+ isInvalid && h ( 'div' , { 'data-testid' : 'password-error' } , invalidMessage )
381+ ] ) ;
382+ } ,
383+ } ) ) ;
384+
385+ // Mock @preact /signals
386+ vi . mock ( '@preact/signals' , async ( useOriginal ) => {
387+ const original = await useOriginal ( ) ;
388+ return {
389+ ...( typeof original === 'object' && original !== null ? original : { } ) ,
390+ signal : ( value : unknown ) => ( {
391+ value,
392+ } ) ,
393+ }
394+ } ) ;
395+
321396beforeAll ( ( ) => {
322397 // Setup any global test configuration here
398+
399+ // Mock localStorage
400+ const localStorageMock = {
401+ getItem : vi . fn ( ) ,
402+ setItem : vi . fn ( ) ,
403+ removeItem : vi . fn ( ) ,
404+ clear : vi . fn ( ) ,
405+ } ;
406+ Object . defineProperty ( window , 'localStorage' , {
407+ value : localStorageMock ,
408+ } ) ;
409+
410+ // Mock window.location.reload
411+ Object . defineProperty ( window , 'location' , {
412+ value : {
413+ reload : vi . fn ( ) ,
414+ href : 'http://localhost:3000' ,
415+ } ,
416+ writable : true ,
417+ } ) ;
418+
419+ // Mock console methods to reduce noise in tests
420+ vi . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } ) ;
421+ vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
323422} ) ;
0 commit comments