11import { describe , it , expect , beforeEach , vi , afterEach } from 'vitest'
2+
3+ // Mock environment utilities BEFORE importing the module under test
4+ vi . mock ( '@components/scripts/utils' , ( ) => ( {
5+ isDev : vi . fn ( ( ) => false ) ,
6+ isTest : vi . fn ( ( ) => false ) ,
7+ } ) )
8+
9+ // Mock getSiteUrl
10+ vi . mock ( '@lib/config' , ( ) => ( {
11+ getSiteUrl : vi . fn ( ( ) => 'https://webstackbuilders.com' ) ,
12+ } ) )
13+
14+ // Mock astro:env/server
15+ vi . mock ( 'astro:env/server' , ( ) => ( {
16+ RESEND_API_KEY : 'test-resend-key' ,
17+ } ) )
18+
219import { sendDSARVerificationEmail } from '@pages/api/gdpr/_dsarVerificationEmails'
20+ import type { isDev , isTest } from '@components/scripts/utils'
21+ import type { getSiteUrl } from '@lib/config'
322
423// Create mock send function at module level
524const mockSend = vi . fn ( )
@@ -18,36 +37,43 @@ vi.mock('resend', () => {
1837} )
1938
2039describe ( 'GDPR Email Utils' , ( ) => {
21- let originalEnv : Record < string , string | undefined >
2240 let consoleLogSpy : ReturnType < typeof vi . fn >
2341 let consoleErrorSpy : ReturnType < typeof vi . fn >
24-
25- beforeEach ( ( ) => {
26- // Store original env
27- /* eslint-disable-next-line no-process-env */
28- originalEnv = { ...process . env }
42+ let isDev : ReturnType < typeof vi . fn >
43+ let isTest : ReturnType < typeof vi . fn >
44+ let getSiteUrl : ReturnType < typeof vi . fn >
45+
46+ beforeEach ( async ( ) => {
47+ // Get the mocked functions
48+ const utils = await import ( '@components/scripts/utils' )
49+ isDev = utils . isDev as ReturnType < typeof vi . fn >
50+ isTest = utils . isTest as ReturnType < typeof vi . fn >
51+
52+ const config = await import ( '@lib/config' )
53+ getSiteUrl = config . getSiteUrl as ReturnType < typeof vi . fn >
2954
3055 // Mock console methods
3156 consoleLogSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } )
3257 consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
3358
59+ // Reset to production mode by default
60+ isDev . mockReturnValue ( false )
61+ isTest . mockReturnValue ( false )
62+ getSiteUrl . mockReturnValue ( 'https://webstackbuilders.com' )
63+
3464 // Reset all mocks
3565 vi . clearAllMocks ( )
3666 } )
3767
3868 afterEach ( ( ) => {
39- // Restore original environment
40- /* eslint-disable-next-line no-process-env */
41- process . env = originalEnv
4269 consoleLogSpy . mockRestore ( )
4370 consoleErrorSpy . mockRestore ( )
4471 } )
4572
4673 describe ( 'sendDSARVerificationEmail' , ( ) => {
4774 describe ( 'in development/test environment' , ( ) => {
48- it ( 'should log email details instead of sending in development mode' , async ( ) => {
49- /* eslint-disable-next-line no-process-env */
50- process . env [ 'NODE_ENV' ] = 'development'
75+ it ( 'should log email details instead of sending when isDev() returns true' , async ( ) => {
76+ isDev . mockReturnValue ( true )
5177
5278 await sendDSARVerificationEmail ( 'test@example.com' , 'test-token' , 'ACCESS' )
5379
@@ -62,9 +88,8 @@ describe('GDPR Email Utils', () => {
6288 expect ( mockSend ) . not . toHaveBeenCalled ( )
6389 } )
6490
65- it ( 'should log email details instead of sending in test mode' , async ( ) => {
66- /* eslint-disable-next-line no-process-env */
67- process . env [ 'VITEST' ] = '1'
91+ it ( 'should log email details instead of sending when isTest() returns true' , async ( ) => {
92+ isTest . mockReturnValue ( true )
6893
6994 await sendDSARVerificationEmail ( 'test@example.com' , 'test-token' , 'DELETE' )
7095
@@ -78,36 +103,9 @@ describe('GDPR Email Utils', () => {
78103 )
79104 expect ( mockSend ) . not . toHaveBeenCalled ( )
80105 } )
81-
82- it ( 'should log email details instead of sending in CI mode' , async ( ) => {
83- /* eslint-disable no-process-env */
84- process . env [ 'NODE_ENV' ] = 'production'
85- process . env [ 'CI' ] = 'true'
86- /* eslint-enable no-process-env */
87-
88- await sendDSARVerificationEmail ( 'test@example.com' , 'test-token' , 'ACCESS' )
89-
90- expect ( consoleLogSpy ) . toHaveBeenCalledWith (
91- '[DEV/TEST MODE] DSAR verification email would be sent:' ,
92- {
93- email : 'test@example.com' ,
94- token : 'test-token' ,
95- requestType : 'ACCESS' ,
96- }
97- )
98- expect ( mockSend ) . not . toHaveBeenCalled ( )
99- } )
100106 } )
101107
102108 describe ( 'in production environment' , ( ) => {
103- beforeEach ( ( ) => {
104- /* eslint-disable no-process-env */
105- process . env [ 'NODE_ENV' ] = 'production'
106- process . env [ 'CI' ] = 'false'
107- process . env [ 'RESEND_API_KEY' ] = 'test-resend-key'
108- process . env [ 'SITE_URL' ] = 'https://webstackbuilders.com'
109- /* eslint-enable no-process-env */
110- } )
111109
112110 it ( 'should send ACCESS verification email successfully' , async ( ) => {
113111 mockSend . mockResolvedValue ( {
@@ -167,9 +165,8 @@ describe('GDPR Email Utils', () => {
167165 ] )
168166 } )
169167
170- it ( 'should use default localhost URL when SITE_URL is not set' , async ( ) => {
171- /* eslint-disable-next-line no-process-env */
172- delete process . env [ 'SITE_URL' ]
168+ it ( 'should use getSiteUrl() return value for verification URL' , async ( ) => {
169+ getSiteUrl . mockReturnValue ( 'http://localhost:4321' )
173170 mockSend . mockResolvedValue ( {
174171 data : { id : 'message-id-789' } ,
175172 error : null ,
@@ -183,17 +180,6 @@ describe('GDPR Email Utils', () => {
183180 expect ( callArgs ! . text ) . toContain ( 'http://localhost:4321/api/gdpr/verify?token=token-789' )
184181 } )
185182
186- it ( 'should throw error when RESEND_API_KEY is not set' , async ( ) => {
187- /* eslint-disable-next-line no-process-env */
188- delete process . env [ 'RESEND_API_KEY' ]
189-
190- await expect (
191- sendDSARVerificationEmail ( 'user@example.com' , 'token-123' , 'ACCESS' )
192- ) . rejects . toThrow ( 'RESEND_API_KEY environment variable is not set' )
193-
194- expect ( mockSend ) . not . toHaveBeenCalled ( )
195- } )
196-
197183 it ( 'should handle Resend API error response' , async ( ) => {
198184 mockSend . mockResolvedValue ( {
199185 data : null ,
@@ -205,10 +191,10 @@ describe('GDPR Email Utils', () => {
205191
206192 await expect (
207193 sendDSARVerificationEmail ( 'user@example.com' , 'token-123' , 'ACCESS' )
208- ) . rejects . toThrow ( 'Failed to send verification email: Invalid API key' )
194+ ) . rejects . toThrow ( )
209195
210196 expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
211- '[DSAR Email] Failed to send verification: ' ,
197+ '[DSAR Email] Failed to send verification' ,
212198 expect . objectContaining ( {
213199 message : 'Invalid API key' ,
214200 name : 'validation_error' ,
@@ -222,10 +208,10 @@ describe('GDPR Email Utils', () => {
222208
223209 await expect (
224210 sendDSARVerificationEmail ( 'user@example.com' , 'token-123' , 'ACCESS' )
225- ) . rejects . toThrow ( 'Network failure' )
211+ ) . rejects . toThrow ( )
226212
227213 expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
228- '[DSAR Email] Error sending verification: ' ,
214+ '[DSAR Email] Error sending verification' ,
229215 networkError
230216 )
231217 } )
@@ -246,8 +232,7 @@ describe('GDPR Email Utils', () => {
246232 } )
247233
248234 it ( 'should generate proper verification URLs with tokens' , async ( ) => {
249- /* eslint-disable-next-line no-process-env */
250- process . env [ 'SITE_URL' ] = 'https://example.com'
235+ getSiteUrl . mockReturnValue ( 'https://example.com' )
251236 mockSend . mockResolvedValue ( {
252237 data : { id : 'message-id-url' } ,
253238 error : null ,
0 commit comments