Skip to content

Commit 75b11d7

Browse files
committed
improvement(tests): speed up unit tests by eliminating vi.resetModules anti-pattern
- convert 51 test files from vi.resetModules/vi.doMock/dynamic import to vi.hoisted/vi.mock/static import - add global @sim/db mock to vitest.setup.ts - switch 4 test files from jsdom to node environment - remove all vi.importActual calls that loaded heavy modules (200+ block files) - remove slow mockConsoleLogger/mockAuth/setupCommonApiMocks helpers - reduce real setTimeout delays in engine tests - mock heavy transitive deps in diff-engine test test execution time: 34s -> 9s (3.9x faster) environment time: 2.5s -> 0.6s (4x faster)
1 parent 67f8a68 commit 75b11d7

File tree

65 files changed

+4945
-5145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+4945
-5145
lines changed

apps/sim/app/api/auth/[...all]/route.test.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { createMockRequest, setupCommonApiMocks } from '@sim/testing'
4+
import { createMockRequest } from '@sim/testing'
55
import { beforeEach, describe, expect, it, vi } from 'vitest'
66

77
const handlerMocks = vi.hoisted(() => ({
@@ -14,6 +14,7 @@ const handlerMocks = vi.hoisted(() => ({
1414
session: { id: 'anon-session' },
1515
},
1616
})),
17+
isAuthDisabled: false,
1718
}))
1819

1920
vi.mock('better-auth/next-js', () => ({
@@ -32,26 +33,29 @@ vi.mock('@/lib/auth/anonymous', () => ({
3233
createAnonymousGetSessionResponse: handlerMocks.createAnonymousGetSessionResponse,
3334
}))
3435

36+
vi.mock('@/lib/core/config/feature-flags', () => ({
37+
get isAuthDisabled() {
38+
return handlerMocks.isAuthDisabled
39+
},
40+
}))
41+
42+
import { GET } from '@/app/api/auth/[...all]/route'
43+
3544
describe('auth catch-all route (DISABLE_AUTH get-session)', () => {
3645
beforeEach(() => {
37-
vi.resetModules()
38-
setupCommonApiMocks()
39-
handlerMocks.betterAuthGET.mockReset()
40-
handlerMocks.betterAuthPOST.mockReset()
41-
handlerMocks.ensureAnonymousUserExists.mockReset()
42-
handlerMocks.createAnonymousGetSessionResponse.mockClear()
46+
vi.clearAllMocks()
47+
handlerMocks.isAuthDisabled = false
4348
})
4449

4550
it('returns anonymous session in better-auth response envelope when auth is disabled', async () => {
46-
vi.doMock('@/lib/core/config/feature-flags', () => ({ isAuthDisabled: true }))
51+
handlerMocks.isAuthDisabled = true
4752

4853
const req = createMockRequest(
4954
'GET',
5055
undefined,
5156
{},
5257
'http://localhost:3000/api/auth/get-session'
5358
)
54-
const { GET } = await import('@/app/api/auth/[...all]/route')
5559

5660
const res = await GET(req as any)
5761
const json = await res.json()
@@ -67,10 +71,11 @@ describe('auth catch-all route (DISABLE_AUTH get-session)', () => {
6771
})
6872

6973
it('delegates to better-auth handler when auth is enabled', async () => {
70-
vi.doMock('@/lib/core/config/feature-flags', () => ({ isAuthDisabled: false }))
74+
handlerMocks.isAuthDisabled = false
7175

76+
const { NextResponse } = await import('next/server')
7277
handlerMocks.betterAuthGET.mockResolvedValueOnce(
73-
new (await import('next/server')).NextResponse(JSON.stringify({ data: { ok: true } }), {
78+
new NextResponse(JSON.stringify({ data: { ok: true } }), {
7479
headers: { 'content-type': 'application/json' },
7580
}) as any
7681
)
@@ -81,7 +86,6 @@ describe('auth catch-all route (DISABLE_AUTH get-session)', () => {
8186
{},
8287
'http://localhost:3000/api/auth/get-session'
8388
)
84-
const { GET } = await import('@/app/api/auth/[...all]/route')
8589

8690
const res = await GET(req as any)
8791
const json = await res.json()

apps/sim/app/api/auth/forget-password/route.test.ts

Lines changed: 37 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -3,91 +3,64 @@
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'
147
import { 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

6041
describe('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

Comments
 (0)