11/**
22 * Unit tests for newsletter confirmation API endpoint
33 */
4- import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest'
4+ import { describe , it , expect , vi , beforeEach , afterEach , type Mock } from 'vitest'
55import type { APIContext } from 'astro'
66import { GET } from '../confirm'
77
88// Mock dependencies
9- vi . mock ( '../../../../../ api/newsletter/token' , ( ) => ( {
9+ vi . mock ( '@ api/newsletter/token' , ( ) => ( {
1010 confirmSubscription : vi . fn ( ) ,
1111} ) )
1212
13- vi . mock ( '../../../../../ api/shared/consent-log' , ( ) => ( {
13+ vi . mock ( '@ api/shared/consent-log' , ( ) => ( {
1414 recordConsent : vi . fn ( ) ,
1515} ) )
1616
17- vi . mock ( '../../../../../ api/newsletter/email' , ( ) => ( {
17+ vi . mock ( '@ api/newsletter/email' , ( ) => ( {
1818 sendWelcomeEmail : vi . fn ( ) ,
1919} ) )
2020
21- vi . mock ( '../../../../../ api/newsletter/newsletter' , ( ) => ( {
21+ vi . mock ( '@ api/newsletter/newsletter' , ( ) => ( {
2222 subscribeToConvertKit : vi . fn ( ) ,
2323} ) )
2424
25- const { confirmSubscription } = await import ( '../../../../api/newsletter/token' )
26- const { recordConsent } = await import ( '../../../../api/shared/consent-log' )
27- const { sendWelcomeEmail } = await import ( '../../../../api/newsletter/email' )
25+ const tokenModule = await import ( '@api/newsletter/token' )
26+ const consentModule = await import ( '@api/shared/consent-log' )
27+ const emailModule = await import ( '@api/newsletter/email' )
28+
29+ const mockConfirmSubscription = tokenModule . confirmSubscription as Mock
30+ const mockRecordConsent = consentModule . recordConsent as Mock
31+ const mockSendWelcomeEmail = emailModule . sendWelcomeEmail as Mock
2832
2933describe ( 'Newsletter Confirmation API - GET /api/newsletter/confirm' , ( ) => {
3034 beforeEach ( ( ) => {
@@ -34,7 +38,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
3438 vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
3539 vi . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } )
3640
37- vi . mocked ( recordConsent ) . mockResolvedValue ( {
41+ mockRecordConsent . mockResolvedValue ( {
3842 id : 'test-consent-id' ,
3943 email : 'test@example.com' ,
4044 purposes : [ 'marketing' ] ,
@@ -44,7 +48,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
4448 privacyPolicyVersion : '2025-10-20' ,
4549 verified : true ,
4650 } )
47- vi . mocked ( sendWelcomeEmail ) . mockResolvedValue ( undefined )
51+ mockSendWelcomeEmail . mockResolvedValue ( undefined )
4852 } )
4953
5054 afterEach ( ( ) => {
@@ -65,7 +69,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
6569 source : 'newsletter_form' as const ,
6670 }
6771
68- vi . mocked ( confirmSubscription ) . mockResolvedValue ( mockSubscription )
72+ mockConfirmSubscription . mockResolvedValue ( mockSubscription )
6973
7074 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=valid-token-123' )
7175 const response = await GET ( { url } as Partial < APIContext > as APIContext )
@@ -78,7 +82,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
7882 expect ( data . message ) . toContain ( 'confirmed' )
7983
8084 // Verify consent was recorded as verified
81- expect ( recordConsent ) . toHaveBeenCalledWith (
85+ expect ( mockRecordConsent ) . toHaveBeenCalledWith (
8286 expect . objectContaining ( {
8387 email : 'test@example.com' ,
8488 purposes : [ 'marketing' ] ,
@@ -88,7 +92,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
8892 )
8993
9094 // Verify welcome email was sent
91- expect ( sendWelcomeEmail ) . toHaveBeenCalledWith ( 'test@example.com' , 'John' )
95+ expect ( mockSendWelcomeEmail ) . toHaveBeenCalledWith ( 'test@example.com' , 'John' )
9296 } )
9397
9498 it ( 'should reject request without token' , async ( ) => {
@@ -103,7 +107,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
103107 } )
104108
105109 it ( 'should handle expired or invalid token' , async ( ) => {
106- vi . mocked ( confirmSubscription ) . mockResolvedValue ( null )
110+ mockConfirmSubscription . mockResolvedValue ( null )
107111
108112 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=expired-token' )
109113 const response = await GET ( { url } as Partial < APIContext > as APIContext )
@@ -127,15 +131,15 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
127131 source : 'newsletter_form' as const ,
128132 }
129133
130- vi . mocked ( confirmSubscription ) . mockResolvedValue ( mockSubscription )
134+ mockConfirmSubscription . mockResolvedValue ( mockSubscription )
131135
132136 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=valid-token-123' )
133137 const response = await GET ( { url } as Partial < APIContext > as APIContext )
134138 const data = await response . json ( )
135139
136140 expect ( response . status ) . toBe ( 200 )
137141 expect ( data . success ) . toBe ( true )
138- expect ( sendWelcomeEmail ) . toHaveBeenCalledWith ( 'test@example.com' , undefined )
142+ expect ( mockSendWelcomeEmail ) . toHaveBeenCalledWith ( 'test@example.com' , undefined )
139143 } )
140144
141145 it ( 'should handle subscription without ipAddress' , async ( ) => {
@@ -151,20 +155,20 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
151155 source : 'newsletter_form' as const ,
152156 }
153157
154- vi . mocked ( confirmSubscription ) . mockResolvedValue ( mockSubscription )
158+ mockConfirmSubscription . mockResolvedValue ( mockSubscription )
155159
156160 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=valid-token-123' )
157161 const response = await GET ( { url } as Partial < APIContext > as APIContext )
158162
159163 expect ( response . status ) . toBe ( 200 )
160- expect ( recordConsent ) . toHaveBeenCalledWith (
164+ expect ( mockRecordConsent ) . toHaveBeenCalledWith (
161165 expect . objectContaining ( {
162166 email : 'test@example.com' ,
163167 verified : true ,
164168 } ) ,
165169 )
166170 // Should not have ipAddress in the call
167- expect ( recordConsent ) . toHaveBeenCalledWith (
171+ expect ( mockRecordConsent ) . toHaveBeenCalledWith (
168172 expect . not . objectContaining ( {
169173 ipAddress : expect . anything ( ) ,
170174 } ) ,
@@ -184,8 +188,8 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
184188 source : 'newsletter_form' as const ,
185189 }
186190
187- vi . mocked ( confirmSubscription ) . mockResolvedValue ( mockSubscription )
188- vi . mocked ( sendWelcomeEmail ) . mockRejectedValue ( new Error ( 'Email service down' ) )
191+ mockConfirmSubscription . mockResolvedValue ( mockSubscription )
192+ mockSendWelcomeEmail . mockRejectedValue ( new Error ( 'Email service down' ) )
189193
190194 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=valid-token-123' )
191195 const response = await GET ( { url } as Partial < APIContext > as APIContext )
@@ -197,7 +201,7 @@ describe('Newsletter Confirmation API - GET /api/newsletter/confirm', () => {
197201 } )
198202
199203 it ( 'should handle confirmation service errors' , async ( ) => {
200- vi . mocked ( confirmSubscription ) . mockRejectedValue ( new Error ( 'Database error' ) )
204+ mockConfirmSubscription . mockRejectedValue ( new Error ( 'Database error' ) )
201205
202206 const url = new URL ( 'http://localhost/api/newsletter/confirm?token=valid-token-123' )
203207 const response = await GET ( { url } as Partial < APIContext > as APIContext )
0 commit comments