11import { describe , it , expect , beforeEach , vi , afterEach } from 'vitest'
22import { sendDSARVerificationEmail } from '@pages/api/_utils/gdpr-email'
33
4+ // Create mock send function at module level
5+ const mockSend = vi . fn ( )
6+
47// Mock the Resend module
58vi . mock ( 'resend' , ( ) => {
6- const mockSend = vi . fn ( )
79 return {
8- Resend : vi . fn ( ) . mockImplementation ( ( ) => ( {
9- emails : {
10- send : mockSend ,
11- } ,
12- } ) ) ,
10+ Resend : vi . fn ( function ResendMock ( _apiKey ) {
11+ return {
12+ emails : {
13+ send : mockSend ,
14+ } ,
15+ }
16+ } ) ,
1317 }
1418} )
1519
1620describe ( 'GDPR Email Utils' , ( ) => {
17- let mockResendSend : ReturnType < typeof vi . fn >
1821 let originalEnv : Record < string , string | undefined >
1922 let consoleLogSpy : ReturnType < typeof vi . fn >
2023 let consoleErrorSpy : ReturnType < typeof vi . fn >
2124
22- beforeEach ( async ( ) => {
25+ beforeEach ( ( ) => {
2326 // Store original env
2427 originalEnv = { ...process . env }
2528
2629 // Mock console methods
2730 consoleLogSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } )
2831 consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
2932
30- // Get the mock function from the mocked Resend class
31- const { Resend } = await import ( 'resend' )
32- const resendInstance = new Resend ( 'test-key' )
33- mockResendSend = resendInstance . emails . send as ReturnType < typeof vi . fn >
34-
3533 // Reset all mocks
3634 vi . clearAllMocks ( )
3735 } )
@@ -58,7 +56,7 @@ describe('GDPR Email Utils', () => {
5856 requestType : 'ACCESS' ,
5957 }
6058 )
61- expect ( mockResendSend ) . not . toHaveBeenCalled ( )
59+ expect ( mockSend ) . not . toHaveBeenCalled ( )
6260 } )
6361
6462 it ( 'should log email details instead of sending in test mode' , async ( ) => {
@@ -74,7 +72,7 @@ describe('GDPR Email Utils', () => {
7472 requestType : 'DELETE' ,
7573 }
7674 )
77- expect ( mockResendSend ) . not . toHaveBeenCalled ( )
75+ expect ( mockSend ) . not . toHaveBeenCalled ( )
7876 } )
7977
8078 it ( 'should log email details instead of sending in CI mode' , async ( ) => {
@@ -91,7 +89,7 @@ describe('GDPR Email Utils', () => {
9189 requestType : 'ACCESS' ,
9290 }
9391 )
94- expect ( mockResendSend ) . not . toHaveBeenCalled ( )
92+ expect ( mockSend ) . not . toHaveBeenCalled ( )
9593 } )
9694 } )
9795
@@ -104,15 +102,15 @@ describe('GDPR Email Utils', () => {
104102 } )
105103
106104 it ( 'should send ACCESS verification email successfully' , async ( ) => {
107- mockResendSend . mockResolvedValue ( {
105+ mockSend . mockResolvedValue ( {
108106 data : { id : 'message-id-123' } ,
109107 error : null ,
110108 } )
111109
112110 await sendDSARVerificationEmail ( 'user@example.com' , 'verification-token-123' , 'ACCESS' )
113111
114- expect ( mockResendSend ) . toHaveBeenCalledTimes ( 1 )
115- const callArgs = mockResendSend . mock . calls [ 0 ] ?. [ 0 ]
112+ expect ( mockSend ) . toHaveBeenCalledTimes ( 1 )
113+ const callArgs = mockSend . mock . calls [ 0 ] ?. [ 0 ]
116114 expect ( callArgs ) . toBeDefined ( )
117115
118116 expect ( callArgs ! . from ) . toBe ( 'Webstack Builders <privacy@webstackbuilders.com>' )
@@ -138,15 +136,15 @@ describe('GDPR Email Utils', () => {
138136 } )
139137
140138 it ( 'should send DELETE verification email successfully with warning' , async ( ) => {
141- mockResendSend . mockResolvedValue ( {
139+ mockSend . mockResolvedValue ( {
142140 data : { id : 'message-id-456' } ,
143141 error : null ,
144142 } )
145143
146144 await sendDSARVerificationEmail ( 'user@example.com' , 'delete-token-456' , 'DELETE' )
147145
148- expect ( mockResendSend ) . toHaveBeenCalledTimes ( 1 )
149- const callArgs = mockResendSend . mock . calls [ 0 ] ?. [ 0 ]
146+ expect ( mockSend ) . toHaveBeenCalledTimes ( 1 )
147+ const callArgs = mockSend . mock . calls [ 0 ] ?. [ 0 ]
150148 expect ( callArgs ) . toBeDefined ( )
151149
152150 expect ( callArgs ! . subject ) . toBe ( 'Verify Your Data Deletion Request - Webstack Builders' )
@@ -163,14 +161,14 @@ describe('GDPR Email Utils', () => {
163161
164162 it ( 'should use default localhost URL when SITE_URL is not set' , async ( ) => {
165163 delete process . env [ 'SITE_URL' ]
166- mockResendSend . mockResolvedValue ( {
164+ mockSend . mockResolvedValue ( {
167165 data : { id : 'message-id-789' } ,
168166 error : null ,
169167 } )
170168
171169 await sendDSARVerificationEmail ( 'user@example.com' , 'token-789' , 'ACCESS' )
172170
173- const callArgs = mockResendSend . mock . calls [ 0 ] ?. [ 0 ]
171+ const callArgs = mockSend . mock . calls [ 0 ] ?. [ 0 ]
174172 expect ( callArgs ) . toBeDefined ( )
175173 expect ( callArgs ! . html ) . toContain ( 'http://localhost:4321/api/gdpr/verify?token=token-789' )
176174 expect ( callArgs ! . text ) . toContain ( 'http://localhost:4321/api/gdpr/verify?token=token-789' )
@@ -183,11 +181,11 @@ describe('GDPR Email Utils', () => {
183181 sendDSARVerificationEmail ( 'user@example.com' , 'token-123' , 'ACCESS' )
184182 ) . rejects . toThrow ( 'RESEND_API_KEY environment variable is not set' )
185183
186- expect ( mockResendSend ) . not . toHaveBeenCalled ( )
184+ expect ( mockSend ) . not . toHaveBeenCalled ( )
187185 } )
188186
189187 it ( 'should handle Resend API error response' , async ( ) => {
190- mockResendSend . mockResolvedValue ( {
188+ mockSend . mockResolvedValue ( {
191189 data : null ,
192190 error : {
193191 message : 'Invalid API key' ,
@@ -210,7 +208,7 @@ describe('GDPR Email Utils', () => {
210208
211209 it ( 'should handle Resend API network error' , async ( ) => {
212210 const networkError = new Error ( 'Network failure' )
213- mockResendSend . mockRejectedValue ( networkError )
211+ mockSend . mockRejectedValue ( networkError )
214212
215213 await expect (
216214 sendDSARVerificationEmail ( 'user@example.com' , 'token-123' , 'ACCESS' )
@@ -224,29 +222,29 @@ describe('GDPR Email Utils', () => {
224222
225223 it ( 'should include current year in email content' , async ( ) => {
226224 const currentYear = new Date ( ) . getFullYear ( )
227- mockResendSend . mockResolvedValue ( {
225+ mockSend . mockResolvedValue ( {
228226 data : { id : 'message-id-year' } ,
229227 error : null ,
230228 } )
231229
232230 await sendDSARVerificationEmail ( 'user@example.com' , 'token-year' , 'ACCESS' )
233231
234- const callArgs = mockResendSend . mock . calls [ 0 ] ?. [ 0 ]
232+ const callArgs = mockSend . mock . calls [ 0 ] ?. [ 0 ]
235233 expect ( callArgs ) . toBeDefined ( )
236234 expect ( callArgs ! . html ) . toContain ( `© ${ currentYear } Webstack Builders` )
237235 expect ( callArgs ! . text ) . toContain ( `© ${ currentYear } Webstack Builders` )
238236 } )
239237
240238 it ( 'should generate proper verification URLs with tokens' , async ( ) => {
241239 process . env [ 'SITE_URL' ] = 'https://example.com'
242- mockResendSend . mockResolvedValue ( {
240+ mockSend . mockResolvedValue ( {
243241 data : { id : 'message-id-url' } ,
244242 error : null ,
245243 } )
246244
247245 await sendDSARVerificationEmail ( 'user@example.com' , 'special-token-123' , 'DELETE' )
248246
249- const callArgs = mockResendSend . mock . calls [ 0 ] ?. [ 0 ]
247+ const callArgs = mockSend . mock . calls [ 0 ] ?. [ 0 ]
250248 expect ( callArgs ) . toBeDefined ( )
251249 const expectedUrl = 'https://example.com/api/gdpr/verify?token=special-token-123'
252250
0 commit comments