Skip to content

Commit d4ce81e

Browse files
committed
Fix mocking errors with upgrade to vitest
1 parent 53986eb commit d4ce81e

4 files changed

Lines changed: 54 additions & 44 deletions

File tree

‎src/pages/api/contact/__tests__/index.spec.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Unit tests for contact form 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'
55
import { POST, OPTIONS } from '../index'
66

77
// Mock Resend before importing the module
@@ -18,17 +18,18 @@ vi.mock('resend', () => {
1818
})
1919

2020
// Mock dependencies
21-
vi.mock('../../../../../api/shared/consent-log', () => ({
21+
vi.mock('@api/shared/consent-log', () => ({
2222
recordConsent: vi.fn(),
2323
}))
2424

25-
const { recordConsent } = await import('../../../../api/shared/consent-log')
25+
const consentModule = await import('@api/shared/consent-log')
26+
const mockRecordConsent = consentModule.recordConsent as Mock
2627

2728
describe('Contact API - POST /api/contact', () => {
2829
beforeEach(() => {
2930
vi.clearAllMocks()
3031
mockSend.mockResolvedValue({ data: { id: 'test-email-id' } })
31-
vi.mocked(recordConsent).mockResolvedValue({
32+
mockRecordConsent.mockResolvedValue({
3233
id: 'test-consent-id',
3334
email: 'test@example.com',
3435
purposes: ['contact'],
@@ -293,7 +294,7 @@ describe('Contact API - POST /api/contact', () => {
293294

294295
await POST({ request } as any)
295296

296-
expect(recordConsent).toHaveBeenCalledWith(
297+
expect(mockRecordConsent).toHaveBeenCalledWith(
297298
expect.objectContaining({
298299
email: 'test@example.com',
299300
purposes: ['contact'],
@@ -319,7 +320,7 @@ describe('Contact API - POST /api/contact', () => {
319320

320321
await POST({ request } as any)
321322

322-
expect(recordConsent).not.toHaveBeenCalled()
323+
expect(mockRecordConsent).not.toHaveBeenCalled()
323324
})
324325
})
325326

‎src/pages/api/newsletter/__tests__/confirm.spec.ts‎

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
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'
55
import type { APIContext } from 'astro'
66
import { 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

2933
describe('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)

‎src/pages/api/newsletter/__tests__/index.spec.ts‎

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
/**
22
* Unit tests for newsletter subscription 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'
55
import { POST, OPTIONS } from '../index'
66

77
// Mock dependencies
8-
vi.mock('../../../../../api/newsletter/token', () => ({
8+
vi.mock('@api/newsletter/token', () => ({
99
createPendingSubscription: vi.fn(),
1010
}))
1111

12-
vi.mock('../../../../../api/newsletter/email', () => ({
12+
vi.mock('@api/newsletter/email', () => ({
1313
sendConfirmationEmail: vi.fn(),
1414
}))
1515

16-
vi.mock('../../../../../api/shared/consent-log', () => ({
16+
vi.mock('@api/shared/consent-log', () => ({
1717
recordConsent: vi.fn(),
1818
}))
1919

20-
const { createPendingSubscription } = await import('../../../../api/newsletter/token')
21-
const { sendConfirmationEmail } = await import('../../../../api/newsletter/email')
22-
const { recordConsent } = await import('../../../../api/shared/consent-log')
20+
const tokenModule = await import('@api/newsletter/token')
21+
const emailModule = await import('@api/newsletter/email')
22+
const consentModule = await import('@api/shared/consent-log')
23+
24+
const mockCreatePendingSubscription = tokenModule.createPendingSubscription as Mock
25+
const mockSendConfirmationEmail = emailModule.sendConfirmationEmail as Mock
26+
const mockRecordConsent = consentModule.recordConsent as Mock
2327

2428
describe('Newsletter API - POST /api/newsletter', () => {
2529
beforeEach(() => {
@@ -29,9 +33,9 @@ describe('Newsletter API - POST /api/newsletter', () => {
2933
vi.spyOn(console, 'error').mockImplementation(() => {})
3034
vi.spyOn(console, 'warn').mockImplementation(() => {})
3135

32-
vi.mocked(createPendingSubscription).mockResolvedValue('test-token-123')
33-
vi.mocked(sendConfirmationEmail).mockResolvedValue(undefined)
34-
vi.mocked(recordConsent).mockResolvedValue({
36+
mockCreatePendingSubscription.mockResolvedValue('test-token-123')
37+
mockSendConfirmationEmail.mockResolvedValue(undefined)
38+
mockRecordConsent.mockResolvedValue({
3539
id: 'test-consent-id',
3640
email: 'test@example.com',
3741
purposes: ['marketing'],
@@ -71,21 +75,21 @@ describe('Newsletter API - POST /api/newsletter', () => {
7175
expect(data.requiresConfirmation).toBe(true)
7276

7377
// Verify mocks were called correctly
74-
expect(recordConsent).toHaveBeenCalledWith(
78+
expect(mockRecordConsent).toHaveBeenCalledWith(
7579
expect.objectContaining({
7680
email: 'test@example.com',
7781
purposes: ['marketing'],
7882
source: 'newsletter_form',
7983
verified: false,
8084
}),
8185
)
82-
expect(createPendingSubscription).toHaveBeenCalledWith(
86+
expect(mockCreatePendingSubscription).toHaveBeenCalledWith(
8387
expect.objectContaining({
8488
email: 'test@example.com',
8589
firstName: 'John',
8690
}),
8791
)
88-
expect(sendConfirmationEmail).toHaveBeenCalledWith('test@example.com', 'test-token-123', 'John')
92+
expect(mockSendConfirmationEmail).toHaveBeenCalledWith('test@example.com', 'test-token-123', 'John')
8993
})
9094

9195
it('should reject subscription without email', async () => {
@@ -153,7 +157,7 @@ describe('Newsletter API - POST /api/newsletter', () => {
153157

154158
await POST({ request } as any)
155159

156-
expect(recordConsent).toHaveBeenCalledWith(
160+
expect(mockRecordConsent).toHaveBeenCalledWith(
157161
expect.objectContaining({
158162
email: 'test@example.com',
159163
}),
@@ -200,11 +204,11 @@ describe('Newsletter API - POST /api/newsletter', () => {
200204

201205
expect(response.status).toBe(200)
202206
expect(data.success).toBe(true)
203-
expect(sendConfirmationEmail).toHaveBeenCalledWith('test@example.com', 'test-token-123', undefined)
207+
expect(mockSendConfirmationEmail).toHaveBeenCalledWith('test@example.com', 'test-token-123', undefined)
204208
})
205209

206210
it('should handle service errors gracefully', async () => {
207-
vi.mocked(createPendingSubscription).mockRejectedValue(new Error('Service unavailable'))
211+
mockCreatePendingSubscription.mockRejectedValue(new Error('Service unavailable'))
208212

209213
const request = new Request('http://localhost/api/newsletter', {
210214
method: 'POST',

‎vitest.config.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default getViteConfig({
1212
},
1313
resolve: {
1414
alias: {
15+
'@api': resolve(__dirname, './src/api'),
1516
'@assets': resolve(__dirname, './src/assets'),
1617
'@components': resolve(__dirname, './src/components'),
1718
'@content': resolve(__dirname, './src/content'),

0 commit comments

Comments
 (0)