33 *
44 * @vitest -environment node
55 */
6- import {
7- createMockRequest ,
8- mockConsoleLogger ,
9- mockCryptoUuid ,
10- mockDrizzleOrm ,
11- mockUuid ,
12- setupCommonApiMocks ,
13- } from '@sim/testing'
6+ import { createMockRequest } from '@sim/testing'
147import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
158
16- vi . mock ( '@/lib/core/utils/urls' , ( ) => ( {
17- getBaseUrl : vi . fn ( ( ) => 'https://app.example.com' ) ,
18- } ) )
19-
20- /** Setup auth API mocks for testing authentication routes */
21- function setupAuthApiMocks (
22- options : {
23- operations ?: {
24- forgetPassword ?: { success ?: boolean ; error ?: string }
25- resetPassword ?: { success ?: boolean ; error ?: string }
26- }
27- } = { }
28- ) {
29- setupCommonApiMocks ( )
30- mockUuid ( )
31- mockCryptoUuid ( )
32- mockConsoleLogger ( )
33- mockDrizzleOrm ( )
34-
35- const { operations = { } } = options
36- const defaultOperations = {
37- forgetPassword : { success : true , error : 'Forget password error' , ...operations . forgetPassword } ,
38- resetPassword : { success : true , error : 'Reset password error' , ...operations . resetPassword } ,
9+ const { mockForgetPassword, mockLogger } = vi . hoisted ( ( ) => {
10+ const logger = {
11+ info : vi . fn ( ) ,
12+ warn : vi . fn ( ) ,
13+ error : vi . fn ( ) ,
14+ debug : vi . fn ( ) ,
15+ trace : vi . fn ( ) ,
16+ fatal : vi . fn ( ) ,
17+ child : vi . fn ( ) ,
3918 }
40-
41- const createAuthMethod = ( config : { success ?: boolean ; error ?: string } ) => {
42- return vi . fn ( ) . mockImplementation ( ( ) => {
43- if ( config . success ) {
44- return Promise . resolve ( )
45- }
46- return Promise . reject ( new Error ( config . error ) )
47- } )
19+ return {
20+ mockForgetPassword : vi . fn ( ) ,
21+ mockLogger : logger ,
4822 }
23+ } )
4924
50- vi . doMock ( '@/lib/auth' , ( ) => ( {
51- auth : {
52- api : {
53- forgetPassword : createAuthMethod ( defaultOperations . forgetPassword ) ,
54- resetPassword : createAuthMethod ( defaultOperations . resetPassword ) ,
55- } ,
25+ vi . mock ( '@/lib/core/utils/urls' , ( ) => ( {
26+ getBaseUrl : vi . fn ( ( ) => 'https://app.example.com' ) ,
27+ } ) )
28+ vi . mock ( '@/lib/auth' , ( ) => ( {
29+ auth : {
30+ api : {
31+ forgetPassword : mockForgetPassword ,
5632 } ,
57- } ) )
58- }
33+ } ,
34+ } ) )
35+ vi . mock ( '@sim/logger' , ( ) => ( {
36+ createLogger : vi . fn ( ) . mockReturnValue ( mockLogger ) ,
37+ } ) )
38+
39+ import { POST } from '@/app/api/auth/forget-password/route'
5940
6041describe ( 'Forget Password API Route' , ( ) => {
6142 beforeEach ( ( ) => {
62- vi . resetModules ( )
43+ vi . clearAllMocks ( )
44+ mockForgetPassword . mockResolvedValue ( undefined )
6345 } )
6446
6547 afterEach ( ( ) => {
6648 vi . clearAllMocks ( )
6749 } )
6850
6951 it ( 'should send password reset email successfully with same-origin redirectTo' , async ( ) => {
70- setupAuthApiMocks ( {
71- operations : {
72- forgetPassword : { success : true } ,
73- } ,
74- } )
75-
7652 const req = createMockRequest ( 'POST' , {
7753 email : 'test@example.com' ,
7854 redirectTo : 'https://app.example.com/reset' ,
7955 } )
8056
81- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
82-
8357 const response = await POST ( req )
8458 const data = await response . json ( )
8559
8660 expect ( response . status ) . toBe ( 200 )
8761 expect ( data . success ) . toBe ( true )
8862
89- const auth = await import ( '@/lib/auth' )
90- expect ( auth . auth . api . forgetPassword ) . toHaveBeenCalledWith ( {
63+ expect ( mockForgetPassword ) . toHaveBeenCalledWith ( {
9164 body : {
9265 email : 'test@example.com' ,
9366 redirectTo : 'https://app.example.com/reset' ,
@@ -97,50 +70,32 @@ describe('Forget Password API Route', () => {
9770 } )
9871
9972 it ( 'should reject external redirectTo URL' , async ( ) => {
100- setupAuthApiMocks ( {
101- operations : {
102- forgetPassword : { success : true } ,
103- } ,
104- } )
105-
10673 const req = createMockRequest ( 'POST' , {
10774 email : 'test@example.com' ,
10875 redirectTo : 'https://evil.com/phishing' ,
10976 } )
11077
111- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
112-
11378 const response = await POST ( req )
11479 const data = await response . json ( )
11580
11681 expect ( response . status ) . toBe ( 400 )
11782 expect ( data . message ) . toBe ( 'Redirect URL must be a valid same-origin URL' )
11883
119- const auth = await import ( '@/lib/auth' )
120- expect ( auth . auth . api . forgetPassword ) . not . toHaveBeenCalled ( )
84+ expect ( mockForgetPassword ) . not . toHaveBeenCalled ( )
12185 } )
12286
12387 it ( 'should send password reset email without redirectTo' , async ( ) => {
124- setupAuthApiMocks ( {
125- operations : {
126- forgetPassword : { success : true } ,
127- } ,
128- } )
129-
13088 const req = createMockRequest ( 'POST' , {
13189 email : 'test@example.com' ,
13290 } )
13391
134- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
135-
13692 const response = await POST ( req )
13793 const data = await response . json ( )
13894
13995 expect ( response . status ) . toBe ( 200 )
14096 expect ( data . success ) . toBe ( true )
14197
142- const auth = await import ( '@/lib/auth' )
143- expect ( auth . auth . api . forgetPassword ) . toHaveBeenCalledWith ( {
98+ expect ( mockForgetPassword ) . toHaveBeenCalledWith ( {
14499 body : {
145100 email : 'test@example.com' ,
146101 redirectTo : undefined ,
@@ -150,97 +105,64 @@ describe('Forget Password API Route', () => {
150105 } )
151106
152107 it ( 'should handle missing email' , async ( ) => {
153- setupAuthApiMocks ( )
154-
155108 const req = createMockRequest ( 'POST' , { } )
156109
157- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
158-
159110 const response = await POST ( req )
160111 const data = await response . json ( )
161112
162113 expect ( response . status ) . toBe ( 400 )
163114 expect ( data . message ) . toBe ( 'Email is required' )
164115
165- const auth = await import ( '@/lib/auth' )
166- expect ( auth . auth . api . forgetPassword ) . not . toHaveBeenCalled ( )
116+ expect ( mockForgetPassword ) . not . toHaveBeenCalled ( )
167117 } )
168118
169119 it ( 'should handle empty email' , async ( ) => {
170- setupAuthApiMocks ( )
171-
172120 const req = createMockRequest ( 'POST' , {
173121 email : '' ,
174122 } )
175123
176- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
177-
178124 const response = await POST ( req )
179125 const data = await response . json ( )
180126
181127 expect ( response . status ) . toBe ( 400 )
182128 expect ( data . message ) . toBe ( 'Please provide a valid email address' )
183129
184- const auth = await import ( '@/lib/auth' )
185- expect ( auth . auth . api . forgetPassword ) . not . toHaveBeenCalled ( )
130+ expect ( mockForgetPassword ) . not . toHaveBeenCalled ( )
186131 } )
187132
188133 it ( 'should handle auth service error with message' , async ( ) => {
189134 const errorMessage = 'User not found'
190135
191- setupAuthApiMocks ( {
192- operations : {
193- forgetPassword : {
194- success : false ,
195- error : errorMessage ,
196- } ,
197- } ,
198- } )
136+ mockForgetPassword . mockRejectedValue ( new Error ( errorMessage ) )
199137
200138 const req = createMockRequest ( 'POST' , {
201139 email : 'nonexistent@example.com' ,
202140 } )
203141
204- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
205-
206142 const response = await POST ( req )
207143 const data = await response . json ( )
208144
209145 expect ( response . status ) . toBe ( 500 )
210146 expect ( data . message ) . toBe ( errorMessage )
211147
212- const logger = await import ( '@sim/logger' )
213- const mockLogger = logger . createLogger ( 'ForgetPasswordTest' )
214148 expect ( mockLogger . error ) . toHaveBeenCalledWith ( 'Error requesting password reset:' , {
215149 error : expect . any ( Error ) ,
216150 } )
217151 } )
218152
219153 it ( 'should handle unknown error' , async ( ) => {
220- setupAuthApiMocks ( )
221-
222- vi . doMock ( '@/lib/auth' , ( ) => ( {
223- auth : {
224- api : {
225- forgetPassword : vi . fn ( ) . mockRejectedValue ( 'Unknown error' ) ,
226- } ,
227- } ,
228- } ) )
154+ mockForgetPassword . mockRejectedValue ( 'Unknown error' )
229155
230156 const req = createMockRequest ( 'POST' , {
231157 email : 'test@example.com' ,
232158 } )
233159
234- const { POST } = await import ( '@/app/api/auth/forget-password/route' )
235-
236160 const response = await POST ( req )
237161 const data = await response . json ( )
238162
239163 expect ( response . status ) . toBe ( 500 )
240164 expect ( data . message ) . toBe ( 'Failed to send password reset email. Please try again later.' )
241165
242- const logger = await import ( '@sim/logger' )
243- const mockLogger = logger . createLogger ( 'ForgetPasswordTest' )
244166 expect ( mockLogger . error ) . toHaveBeenCalled ( )
245167 } )
246168} )
0 commit comments