Skip to content

Commit dbdaf4f

Browse files
committed
consolidated more test utils
1 parent a0cfad3 commit dbdaf4f

File tree

38 files changed

+189
-583
lines changed

38 files changed

+189
-583
lines changed

.cursor/rules/sim-testing.mdc

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,57 @@
11
---
2-
description: Testing patterns with Vitest
2+
description: Testing patterns with Vitest and @sim/testing
33
globs: ["apps/sim/**/*.test.ts", "apps/sim/**/*.test.tsx"]
44
---
55

66
# Testing Patterns
77

8-
Use Vitest. Test files live next to source: `feature.ts` → `feature.test.ts`
8+
Use Vitest. Test files: `feature.ts` → `feature.test.ts`
99

1010
## Structure
1111

1212
```typescript
1313
/**
14-
* Tests for [feature name]
15-
*
1614
* @vitest-environment node
1715
*/
16+
import { databaseMock, loggerMock } from '@sim/testing'
17+
import { describe, expect, it, vi } from 'vitest'
1818

19-
// 1. Mocks BEFORE imports
20-
vi.mock('@sim/db', () => ({ db: { select: vi.fn() } }))
19+
vi.mock('@sim/db', () => databaseMock)
2120
vi.mock('@sim/logger', () => loggerMock)
2221

23-
// 2. Imports AFTER mocks
24-
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
25-
import { createSession, loggerMock } from '@sim/testing'
2622
import { myFunction } from '@/lib/feature'
2723

2824
describe('myFunction', () => {
2925
beforeEach(() => vi.clearAllMocks())
30-
31-
it('should do something', () => {
32-
expect(myFunction()).toBe(expected)
33-
})
34-
35-
it.concurrent('runs in parallel', () => { ... })
26+
it.concurrent('isolated tests run in parallel', () => { ... })
3627
})
3728
```
3829

3930
## @sim/testing Package
4031

41-
```typescript
42-
// Factories - create test data
43-
import { createBlock, createWorkflow, createSession } from '@sim/testing'
32+
Always prefer over local mocks.
4433

45-
// Mocks - pre-configured mocks
46-
import { loggerMock, databaseMock, fetchMock } from '@sim/testing'
47-
48-
// Builders - fluent API for complex objects
49-
import { ExecutionBuilder, WorkflowBuilder } from '@sim/testing'
50-
```
34+
| Category | Utilities |
35+
|----------|-----------|
36+
| **Mocks** | `loggerMock`, `databaseMock`, `setupGlobalFetchMock()` |
37+
| **Factories** | `createSession()`, `createWorkflowRecord()`, `createBlock()`, `createExecutorContext()` |
38+
| **Builders** | `WorkflowBuilder`, `ExecutionContextBuilder` |
39+
| **Assertions** | `expectWorkflowAccessGranted()`, `expectBlockExecuted()` |
5140

5241
## Rules
5342

5443
1. `@vitest-environment node` directive at file top
55-
2. **Mocks before imports** - `vi.mock()` calls must come first
56-
3. Use `@sim/testing` factories over manual test data
57-
4. `it.concurrent` for independent tests (faster)
44+
2. `vi.mock()` calls before importing mocked modules
45+
3. `@sim/testing` utilities over local mocks
46+
4. `it.concurrent` for isolated tests (no shared mutable state)
5847
5. `beforeEach(() => vi.clearAllMocks())` to reset state
59-
6. Group related tests with nested `describe` blocks
60-
7. Test file naming: `*.test.ts` (not `*.spec.ts`)
48+
49+
## Hoisted Mocks
50+
51+
For mutable mock references:
52+
53+
```typescript
54+
const mockFn = vi.hoisted(() => vi.fn())
55+
vi.mock('@/lib/module', () => ({ myFunction: mockFn }))
56+
mockFn.mockResolvedValue({ data: 'test' })
57+
```

CLAUDE.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,21 +173,21 @@ Use Vitest. Test files: `feature.ts` → `feature.test.ts`
173173
/**
174174
* @vitest-environment node
175175
*/
176+
import { databaseMock, loggerMock } from '@sim/testing'
177+
import { describe, expect, it, vi } from 'vitest'
176178

177-
// Mocks BEFORE imports
178-
vi.mock('@sim/db', () => ({ db: { select: vi.fn() } }))
179+
vi.mock('@sim/db', () => databaseMock)
180+
vi.mock('@sim/logger', () => loggerMock)
179181

180-
// Imports AFTER mocks
181-
import { describe, expect, it, vi } from 'vitest'
182-
import { createSession, loggerMock } from '@sim/testing'
182+
import { myFunction } from '@/lib/feature'
183183

184184
describe('feature', () => {
185185
beforeEach(() => vi.clearAllMocks())
186186
it.concurrent('runs in parallel', () => { ... })
187187
})
188188
```
189189

190-
Use `@sim/testing` factories over manual test data.
190+
Use `@sim/testing` mocks/factories over local test data. See `.cursor/rules/sim-testing.mdc` for details.
191191

192192
## Utils Rules
193193

apps/sim/app/api/chat/[identifier]/route.test.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* @vitest-environment node
55
*/
6+
import { loggerMock } from '@sim/testing'
67
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
78
import { createMockRequest } from '@/app/api/__test-utils__/utils'
89

@@ -120,14 +121,8 @@ describe('Chat Identifier API Route', () => {
120121
validateAuthToken: vi.fn().mockReturnValue(true),
121122
}))
122123

123-
vi.doMock('@sim/logger', () => ({
124-
createLogger: vi.fn().mockReturnValue({
125-
debug: vi.fn(),
126-
info: vi.fn(),
127-
warn: vi.fn(),
128-
error: vi.fn(),
129-
}),
130-
}))
124+
// Mock logger - use loggerMock from @sim/testing
125+
vi.doMock('@sim/logger', () => loggerMock)
131126

132127
vi.doMock('@sim/db', () => {
133128
const mockSelect = vi.fn().mockImplementation((fields) => {

apps/sim/app/api/chat/manage/[id]/route.test.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { NextRequest } from 'next/server'
21
/**
32
* Tests for chat edit API route
43
*
54
* @vitest-environment node
65
*/
6+
import { loggerMock } from '@sim/testing'
7+
import { NextRequest } from 'next/server'
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

910
vi.mock('@/lib/core/config/feature-flags', () => ({
@@ -50,14 +51,8 @@ describe('Chat Edit API Route', () => {
5051
chat: { id: 'id', identifier: 'identifier', userId: 'userId' },
5152
}))
5253

53-
vi.doMock('@sim/logger', () => ({
54-
createLogger: vi.fn().mockReturnValue({
55-
info: vi.fn(),
56-
error: vi.fn(),
57-
warn: vi.fn(),
58-
debug: vi.fn(),
59-
}),
60-
}))
54+
// Mock logger - use loggerMock from @sim/testing
55+
vi.doMock('@sim/logger', () => loggerMock)
6156

6257
vi.doMock('@/app/api/workflows/utils', () => ({
6358
createSuccessResponse: mockCreateSuccessResponse.mockImplementation((data) => {

apps/sim/app/api/chat/utils.test.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { databaseMock, loggerMock } from '@sim/testing'
12
import type { NextResponse } from 'next/server'
23
/**
34
* Tests for chat API utils
@@ -6,12 +7,8 @@ import type { NextResponse } from 'next/server'
67
*/
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

9-
vi.mock('@sim/db', () => ({
10-
db: {
11-
select: vi.fn(),
12-
update: vi.fn(),
13-
},
14-
}))
10+
vi.mock('@sim/db', () => databaseMock)
11+
vi.mock('@sim/logger', () => loggerMock)
1512

1613
vi.mock('@/lib/logs/execution/logging-session', () => ({
1714
LoggingSession: vi.fn().mockImplementation(() => ({
@@ -51,15 +48,6 @@ vi.mock('@/lib/core/config/feature-flags', () => ({
5148

5249
describe('Chat API Utils', () => {
5350
beforeEach(() => {
54-
vi.doMock('@sim/logger', () => ({
55-
createLogger: vi.fn().mockReturnValue({
56-
info: vi.fn(),
57-
error: vi.fn(),
58-
warn: vi.fn(),
59-
debug: vi.fn(),
60-
}),
61-
}))
62-
6351
vi.stubGlobal('process', {
6452
...process,
6553
env: {

apps/sim/app/api/form/utils.test.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { databaseMock, loggerMock } from '@sim/testing'
12
import type { NextResponse } from 'next/server'
23
/**
34
* Tests for form API utils
@@ -6,11 +7,8 @@ import type { NextResponse } from 'next/server'
67
*/
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

9-
vi.mock('@sim/db', () => ({
10-
db: {
11-
select: vi.fn(),
12-
},
13-
}))
10+
vi.mock('@sim/db', () => databaseMock)
11+
vi.mock('@sim/logger', () => loggerMock)
1412

1513
const mockDecryptSecret = vi.fn()
1614

@@ -29,17 +27,6 @@ vi.mock('@/lib/workspaces/permissions/utils', () => ({
2927
}))
3028

3129
describe('Form API Utils', () => {
32-
beforeEach(() => {
33-
vi.doMock('@sim/logger', () => ({
34-
createLogger: vi.fn().mockReturnValue({
35-
info: vi.fn(),
36-
error: vi.fn(),
37-
warn: vi.fn(),
38-
debug: vi.fn(),
39-
}),
40-
}))
41-
})
42-
4330
afterEach(() => {
4431
vi.clearAllMocks()
4532
})

apps/sim/app/api/function/execute/route.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* @vitest-environment node
55
*/
6+
import { loggerMock } from '@sim/testing'
67
import { NextRequest } from 'next/server'
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89
import { createMockRequest } from '@/app/api/__test-utils__/utils'
@@ -82,14 +83,7 @@ vi.mock('@/lib/execution/isolated-vm', () => ({
8283
}),
8384
}))
8485

85-
vi.mock('@sim/logger', () => ({
86-
createLogger: vi.fn(() => ({
87-
info: vi.fn(),
88-
error: vi.fn(),
89-
warn: vi.fn(),
90-
debug: vi.fn(),
91-
})),
92-
}))
86+
vi.mock('@sim/logger', () => loggerMock)
9387

9488
vi.mock('@/lib/execution/e2b', () => ({
9589
executeInE2B: vi.fn(),

apps/sim/app/api/knowledge/search/utils.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,11 @@
44
*
55
* @vitest-environment node
66
*/
7+
import { loggerMock } from '@sim/testing'
78
import { beforeEach, describe, expect, it, vi } from 'vitest'
89

910
vi.mock('drizzle-orm')
10-
vi.mock('@sim/logger', () => ({
11-
createLogger: vi.fn(() => ({
12-
info: vi.fn(),
13-
debug: vi.fn(),
14-
warn: vi.fn(),
15-
error: vi.fn(),
16-
})),
17-
}))
11+
vi.mock('@sim/logger', () => loggerMock)
1812
vi.mock('@sim/db')
1913
vi.mock('@/lib/knowledge/documents/utils', () => ({
2014
retryWithExponentialBackoff: (fn: any) => fn(),

apps/sim/app/api/schedules/[id]/route.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* @vitest-environment node
55
*/
6+
import { loggerMock } from '@sim/testing'
67
import { NextRequest } from 'next/server'
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

@@ -43,14 +44,7 @@ vi.mock('@/lib/core/utils/request', () => ({
4344
generateRequestId: () => 'test-request-id',
4445
}))
4546

46-
vi.mock('@sim/logger', () => ({
47-
createLogger: () => ({
48-
info: vi.fn(),
49-
warn: vi.fn(),
50-
error: vi.fn(),
51-
debug: vi.fn(),
52-
}),
53-
}))
47+
vi.mock('@sim/logger', () => loggerMock)
5448

5549
import { PUT } from './route'
5650

apps/sim/app/api/schedules/route.test.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* @vitest-environment node
55
*/
6+
import { loggerMock } from '@sim/testing'
67
import { NextRequest } from 'next/server'
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

@@ -40,13 +41,7 @@ vi.mock('@/lib/core/utils/request', () => ({
4041
generateRequestId: () => 'test-request-id',
4142
}))
4243

43-
vi.mock('@sim/logger', () => ({
44-
createLogger: () => ({
45-
info: vi.fn(),
46-
warn: vi.fn(),
47-
error: vi.fn(),
48-
}),
49-
}))
44+
vi.mock('@sim/logger', () => loggerMock)
5045

5146
import { GET } from '@/app/api/schedules/route'
5247

0 commit comments

Comments
 (0)