@odvi/create-dtt-framework 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +16 -13
- package/dist/commands/create.js.map +1 -1
- package/package.json +3 -2
- package/template/.env.example +106 -0
- package/template/components.json +22 -0
- package/template/docs/framework/01-overview.md +289 -0
- package/template/docs/framework/02-techstack.md +503 -0
- package/template/docs/framework/api-layer.md +681 -0
- package/template/docs/framework/clerk-authentication.md +649 -0
- package/template/docs/framework/cli-installation.md +564 -0
- package/template/docs/framework/deployment/ci-cd.md +907 -0
- package/template/docs/framework/deployment/digitalocean.md +991 -0
- package/template/docs/framework/deployment/domain-setup.md +972 -0
- package/template/docs/framework/deployment/environment-variables.md +862 -0
- package/template/docs/framework/deployment/monitoring.md +927 -0
- package/template/docs/framework/deployment/production-checklist.md +649 -0
- package/template/docs/framework/deployment/vercel.md +791 -0
- package/template/docs/framework/environment-variables.md +646 -0
- package/template/docs/framework/health-check-system.md +583 -0
- package/template/docs/framework/implementation.md +559 -0
- package/template/docs/framework/snowflake-integration.md +594 -0
- package/template/docs/framework/state-management.md +615 -0
- package/template/docs/framework/supabase-integration.md +582 -0
- package/template/docs/framework/testing-guide.md +544 -0
- package/template/docs/framework/what-did-i-miss.md +526 -0
- package/template/drizzle.config.ts +11 -0
- package/template/next.config.js +21 -0
- package/template/postcss.config.js +5 -0
- package/template/prettier.config.js +4 -0
- package/template/public/favicon.ico +0 -0
- package/template/src/app/(auth)/layout.tsx +4 -0
- package/template/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +10 -0
- package/template/src/app/(auth)/sign-up/[[...sign-up]]/page.tsx +10 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +8 -0
- package/template/src/app/(dashboard)/health/page.tsx +16 -0
- package/template/src/app/(dashboard)/layout.tsx +17 -0
- package/template/src/app/api/[[...route]]/route.ts +11 -0
- package/template/src/app/api/debug-files/route.ts +33 -0
- package/template/src/app/api/webhooks/clerk/route.ts +112 -0
- package/template/src/app/layout.tsx +28 -0
- package/template/src/app/page.tsx +12 -0
- package/template/src/app/providers.tsx +20 -0
- package/template/src/components/layouts/navbar.tsx +14 -0
- package/template/src/components/shared/loading-spinner.tsx +6 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/button.tsx +62 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/collapsible.tsx +33 -0
- package/template/src/components/ui/scroll-area.tsx +58 -0
- package/template/src/components/ui/sheet.tsx +139 -0
- package/template/src/config/__tests__/env.test.ts +164 -0
- package/template/src/config/__tests__/site.test.ts +46 -0
- package/template/src/config/env.ts +36 -0
- package/template/src/config/site.ts +10 -0
- package/template/src/env.js +44 -0
- package/template/src/features/__tests__/health-check-config.test.ts +142 -0
- package/template/src/features/__tests__/health-check-types.test.ts +201 -0
- package/template/src/features/documentation/components/doc-sidebar.tsx +109 -0
- package/template/src/features/documentation/components/doc-viewer.tsx +70 -0
- package/template/src/features/documentation/index.tsx +92 -0
- package/template/src/features/documentation/utils/doc-loader.ts +177 -0
- package/template/src/features/health-check/components/health-dashboard.tsx +374 -0
- package/template/src/features/health-check/config.ts +71 -0
- package/template/src/features/health-check/index.ts +4 -0
- package/template/src/features/health-check/stores/health-store.ts +14 -0
- package/template/src/features/health-check/types.ts +18 -0
- package/template/src/hooks/__tests__/use-debounce.test.tsx +28 -0
- package/template/src/hooks/queries/use-health-checks.ts +16 -0
- package/template/src/hooks/utils/use-debounce.ts +20 -0
- package/template/src/lib/__tests__/utils.test.ts +52 -0
- package/template/src/lib/__tests__/validators.test.ts +114 -0
- package/template/src/lib/nextbank/client.ts +67 -0
- package/template/src/lib/snowflake/client.ts +102 -0
- package/template/src/lib/supabase/admin.ts +7 -0
- package/template/src/lib/supabase/client.ts +7 -0
- package/template/src/lib/supabase/server.ts +23 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/lib/validators.ts +9 -0
- package/template/src/middleware.ts +22 -0
- package/template/src/server/api/index.ts +22 -0
- package/template/src/server/api/middleware/auth.ts +19 -0
- package/template/src/server/api/middleware/logger.ts +4 -0
- package/template/src/server/api/routes/health/clerk.ts +214 -0
- package/template/src/server/api/routes/health/database.ts +141 -0
- package/template/src/server/api/routes/health/edge-functions.ts +107 -0
- package/template/src/server/api/routes/health/framework.ts +48 -0
- package/template/src/server/api/routes/health/index.ts +102 -0
- package/template/src/server/api/routes/health/nextbank.ts +46 -0
- package/template/src/server/api/routes/health/snowflake.ts +83 -0
- package/template/src/server/api/routes/health/storage.ts +177 -0
- package/template/src/server/api/routes/users.ts +79 -0
- package/template/src/server/db/index.ts +17 -0
- package/template/src/server/db/queries/users.ts +8 -0
- package/template/src/server/db/schema/__tests__/health-checks.test.ts +31 -0
- package/template/src/server/db/schema/__tests__/users.test.ts +46 -0
- package/template/src/server/db/schema/health-checks.ts +11 -0
- package/template/src/server/db/schema/index.ts +2 -0
- package/template/src/server/db/schema/users.ts +16 -0
- package/template/src/server/db/schema.ts +1 -0
- package/template/src/stores/__tests__/ui-store.test.ts +87 -0
- package/template/src/stores/ui-store.ts +14 -0
- package/template/src/styles/globals.css +129 -0
- package/template/src/test/mocks/clerk.ts +35 -0
- package/template/src/test/mocks/snowflake.ts +28 -0
- package/template/src/test/mocks/supabase.ts +37 -0
- package/template/src/test/setup.ts +69 -0
- package/template/src/test/utils/test-helpers.ts +158 -0
- package/template/src/types/index.ts +14 -0
- package/template/tsconfig.json +43 -0
- package/template/vitest.config.ts +44 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# DTT Framework - Testing Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide covers the testing infrastructure and practices for DTT Framework. The framework includes a comprehensive test suite with Vitest, React Testing Library, and mocking utilities.
|
|
6
|
+
|
|
7
|
+
### Testing Philosophy
|
|
8
|
+
|
|
9
|
+
- **Test at the right level**: Choose unit, integration, or E2E based on what you're testing
|
|
10
|
+
- **Keep tests fast**: Unit tests should run in milliseconds
|
|
11
|
+
- **Test behavior, not implementation**: Focus on what code does, not how
|
|
12
|
+
- **Use meaningful names**: Test names should describe behavior
|
|
13
|
+
- **Aim for 80% coverage**: Target 80% coverage across lines, functions, branches, and statements
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Testing Infrastructure Setup
|
|
18
|
+
|
|
19
|
+
### Installed Dependencies
|
|
20
|
+
|
|
21
|
+
The framework includes the following testing dependencies:
|
|
22
|
+
|
|
23
|
+
| Tool | Purpose | Version |
|
|
24
|
+
|------|---------|---------|
|
|
25
|
+
| **Vitest** | Unit and integration test runner | ^4.0.16 |
|
|
26
|
+
| **@vitest/ui** | Visual test runner interface | ^4.0.16 |
|
|
27
|
+
| **@vitest/coverage-v8** | Code coverage reporting | ^4.0.16 |
|
|
28
|
+
| **@testing-library/react** | React component testing | ^16.3.1 |
|
|
29
|
+
| **@testing-library/jest-dom** | Custom Jest matchers | ^6.9.1 |
|
|
30
|
+
| **@vitejs/plugin-react** | React plugin for Vitest | ^5.1.2 |
|
|
31
|
+
| **jsdom** | DOM environment for tests | ^27.4.0 |
|
|
32
|
+
| **happy-dom** | Alternative DOM environment | ^20.0.11 |
|
|
33
|
+
| **msw** | API mocking service | ^2.12.7 |
|
|
34
|
+
|
|
35
|
+
### Vitest Configuration
|
|
36
|
+
|
|
37
|
+
The framework uses [`vitest.config.ts`](../../vitest.config.ts) with the following configuration:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { defineConfig } from 'vitest/config';
|
|
41
|
+
import react from '@vitejs/plugin-react';
|
|
42
|
+
import path from 'path';
|
|
43
|
+
|
|
44
|
+
export default defineConfig({
|
|
45
|
+
plugins: [react()],
|
|
46
|
+
test: {
|
|
47
|
+
globals: true,
|
|
48
|
+
environment: 'jsdom',
|
|
49
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
50
|
+
include: ['**/__tests__/**/*.{test,spec}.{ts,tsx}', '**/*.{test,spec}.{ts,tsx}'],
|
|
51
|
+
exclude: ['node_modules', 'dist', '.next', 'coverage'],
|
|
52
|
+
coverage: {
|
|
53
|
+
provider: 'v8',
|
|
54
|
+
reporter: ['text', 'json', 'html', 'lcov'],
|
|
55
|
+
exclude: [
|
|
56
|
+
'node_modules/',
|
|
57
|
+
'.next/',
|
|
58
|
+
'dist/',
|
|
59
|
+
'coverage/',
|
|
60
|
+
'**/*.config.{js,ts}',
|
|
61
|
+
'**/types/**',
|
|
62
|
+
'**/test/**',
|
|
63
|
+
'**/__tests__/**',
|
|
64
|
+
'**/*.d.ts',
|
|
65
|
+
'**/mockData.ts',
|
|
66
|
+
'src/middleware.ts',
|
|
67
|
+
'src/env.js',
|
|
68
|
+
],
|
|
69
|
+
all: true,
|
|
70
|
+
lines: 80,
|
|
71
|
+
functions: 80,
|
|
72
|
+
branches: 80,
|
|
73
|
+
statements: 80,
|
|
74
|
+
},
|
|
75
|
+
testTimeout: 10000,
|
|
76
|
+
hookTimeout: 10000,
|
|
77
|
+
},
|
|
78
|
+
resolve: {
|
|
79
|
+
alias: {
|
|
80
|
+
'@': path.resolve(__dirname, './src'),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Test Setup File
|
|
87
|
+
|
|
88
|
+
The [`src/test/setup.ts`](../../src/test/setup.ts) file configures the test environment:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import '@testing-library/jest-dom';
|
|
92
|
+
import { cleanup } from '@testing-library/react';
|
|
93
|
+
import { afterEach, vi } from 'vitest';
|
|
94
|
+
|
|
95
|
+
// Cleanup after each test
|
|
96
|
+
afterEach(() => {
|
|
97
|
+
cleanup();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Mock window.matchMedia
|
|
101
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
102
|
+
writable: true,
|
|
103
|
+
value: vi.fn().mockImplementation((query) => ({
|
|
104
|
+
matches: false,
|
|
105
|
+
media: query,
|
|
106
|
+
onchange: null,
|
|
107
|
+
addListener: vi.fn(),
|
|
108
|
+
removeListener: vi.fn(),
|
|
109
|
+
addEventListener: vi.fn(),
|
|
110
|
+
removeEventListener: vi.fn(),
|
|
111
|
+
dispatchEvent: vi.fn(),
|
|
112
|
+
})),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Mock IntersectionObserver
|
|
116
|
+
global.IntersectionObserver = class IntersectionObserver {
|
|
117
|
+
constructor() {}
|
|
118
|
+
disconnect() {}
|
|
119
|
+
observe() {}
|
|
120
|
+
takeRecords() {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
unobserve() {}
|
|
124
|
+
} as any;
|
|
125
|
+
|
|
126
|
+
// Mock ResizeObserver
|
|
127
|
+
global.ResizeObserver = class ResizeObserver {
|
|
128
|
+
constructor() {}
|
|
129
|
+
disconnect() {}
|
|
130
|
+
observe() {}
|
|
131
|
+
unobserve() {}
|
|
132
|
+
} as any;
|
|
133
|
+
|
|
134
|
+
// Mock requestAnimationFrame
|
|
135
|
+
global.requestAnimationFrame = (callback: FrameRequestCallback) => {
|
|
136
|
+
return setTimeout(callback, 0) as unknown as number;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
global.cancelAnimationFrame = (id: number) => {
|
|
140
|
+
clearTimeout(id);
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Available Test Scripts
|
|
145
|
+
|
|
146
|
+
| Script | Description |
|
|
147
|
+
|---------|-------------|
|
|
148
|
+
| `pnpm test` | Run all tests once |
|
|
149
|
+
| `pnpm test:watch` | Run tests in watch mode |
|
|
150
|
+
| `pnpm test:ui` | Run tests with visual UI |
|
|
151
|
+
| `pnpm test:coverage` | Run tests with coverage report |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Test Organization
|
|
156
|
+
|
|
157
|
+
### Directory Structure
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/
|
|
161
|
+
├── components/
|
|
162
|
+
│ ├── ui/
|
|
163
|
+
│ │ └── __tests__/ # Component tests
|
|
164
|
+
│ └── layouts/
|
|
165
|
+
│ └── __tests__/ # Layout tests
|
|
166
|
+
├── hooks/
|
|
167
|
+
│ ├── queries/
|
|
168
|
+
│ │ └── __tests__/ # Hook tests
|
|
169
|
+
│ └── utils/
|
|
170
|
+
│ └── __tests__/ # Utility hook tests
|
|
171
|
+
├── lib/
|
|
172
|
+
│ ├── supabase/
|
|
173
|
+
│ │ └── __tests__/ # Supabase client tests
|
|
174
|
+
│ ├── snowflake/
|
|
175
|
+
│ │ └── __tests__/ # Snowflake client tests
|
|
176
|
+
│ ├── nextbank/
|
|
177
|
+
│ │ └── __tests__/ # NextBank client tests
|
|
178
|
+
│ └── __tests__/ # Utility function tests
|
|
179
|
+
├── server/
|
|
180
|
+
│ ├── api/
|
|
181
|
+
│ │ └── routes/
|
|
182
|
+
│ │ └── __tests__/ # API route tests
|
|
183
|
+
│ └── db/
|
|
184
|
+
│ └── schema/
|
|
185
|
+
│ └── __tests__/ # Database schema tests
|
|
186
|
+
├── features/
|
|
187
|
+
│ └── __tests__/ # Feature tests
|
|
188
|
+
├── stores/
|
|
189
|
+
│ └── __tests__/ # Store tests
|
|
190
|
+
├── config/
|
|
191
|
+
│ └── __tests__/ # Config tests
|
|
192
|
+
└── test/
|
|
193
|
+
├── mocks/ # Mock files
|
|
194
|
+
│ ├── supabase.ts
|
|
195
|
+
│ ├── clerk.ts
|
|
196
|
+
│ └── snowflake.ts
|
|
197
|
+
└── utils/ # Test helpers
|
|
198
|
+
└── test-helpers.ts
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Naming Conventions
|
|
202
|
+
|
|
203
|
+
- **Component tests**: `*.test.tsx` or `*.spec.tsx`
|
|
204
|
+
- **Unit tests**: `*.test.ts` or `*.spec.ts`
|
|
205
|
+
- **Test files location**: `__tests__/` directories next to source files
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Running Tests
|
|
210
|
+
|
|
211
|
+
### Run All Tests
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
pnpm test
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Run Tests in Watch Mode
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
pnpm test:watch
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Run Tests with UI
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
pnpm test:ui
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Run Specific Test File
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
pnpm test src/lib/__tests__/utils.test.ts
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Run Tests Matching Pattern
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
pnpm test -- health
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Generate Coverage Report
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
pnpm test:coverage
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This generates:
|
|
248
|
+
- Terminal output with coverage summary
|
|
249
|
+
- HTML report in `coverage/index.html`
|
|
250
|
+
- JSON report in `coverage/coverage-final.json`
|
|
251
|
+
- LCOV report in `coverage/lcov.info`
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Test Files Overview
|
|
256
|
+
|
|
257
|
+
### Utility Tests
|
|
258
|
+
|
|
259
|
+
**File**: [`src/lib/__tests__/utils.test.ts`](../../src/lib/__tests__/utils.test.ts)
|
|
260
|
+
|
|
261
|
+
Tests the `cn` utility function for merging Tailwind CSS classes:
|
|
262
|
+
- Merging class names correctly
|
|
263
|
+
- Handling conditional classes
|
|
264
|
+
- Handling undefined and null values
|
|
265
|
+
- Merging Tailwind classes (later classes override earlier ones)
|
|
266
|
+
- Handling arrays and objects of classes
|
|
267
|
+
- Handling conflicting Tailwind utility classes
|
|
268
|
+
|
|
269
|
+
**File**: [`src/lib/__tests__/validators.test.ts`](../../src/lib/__tests__/validators.test.ts)
|
|
270
|
+
|
|
271
|
+
Tests the `healthCheckSchema` Zod validator:
|
|
272
|
+
- Validating healthy, unhealthy, error, pending, and unconfigured statuses
|
|
273
|
+
- Rejecting invalid status values
|
|
274
|
+
- Validating optional fields (responseTimeMs, message, error)
|
|
275
|
+
- Providing detailed error messages
|
|
276
|
+
|
|
277
|
+
### Hook Tests
|
|
278
|
+
|
|
279
|
+
**File**: [`src/hooks/__tests__/use-debounce.test.tsx`](../../src/hooks/__tests__/use-debounce.test.tsx)
|
|
280
|
+
|
|
281
|
+
Tests the `useDebounce` hook:
|
|
282
|
+
- Returning initial value immediately
|
|
283
|
+
- Cleaning up timer on unmount
|
|
284
|
+
- Handling different delay values
|
|
285
|
+
|
|
286
|
+
### Store Tests
|
|
287
|
+
|
|
288
|
+
**File**: [`src/stores/__tests__/ui-store.test.ts`](../../src/stores/__tests__/ui-store.test.ts)
|
|
289
|
+
|
|
290
|
+
Tests the Zustand UI store:
|
|
291
|
+
- Initial state with sidebar closed
|
|
292
|
+
- Toggling sidebar from closed to open
|
|
293
|
+
- Toggling sidebar from open to closed
|
|
294
|
+
- Multiple toggle operations
|
|
295
|
+
- Providing toggleSidebar function
|
|
296
|
+
- Maintaining state consistency
|
|
297
|
+
- Handling rapid state changes
|
|
298
|
+
- Direct state setting
|
|
299
|
+
|
|
300
|
+
### Config Tests
|
|
301
|
+
|
|
302
|
+
**File**: [`src/config/__tests__/env.test.ts`](../../src/config/__tests__/env.test.ts)
|
|
303
|
+
|
|
304
|
+
Tests the environment configuration schema:
|
|
305
|
+
- Validating environment schema structure
|
|
306
|
+
- Validating NODE_ENV enum values
|
|
307
|
+
- Validating URL fields
|
|
308
|
+
- Validating Clerk key prefixes
|
|
309
|
+
- Allowing optional NextBank fields
|
|
310
|
+
- Validating Snowflake configuration fields
|
|
311
|
+
- Using default values when environment variables are not set
|
|
312
|
+
|
|
313
|
+
**File**: [`src/config/__tests__/site.test.ts`](../../src/config/__tests__/site.test.ts)
|
|
314
|
+
|
|
315
|
+
Tests the site configuration:
|
|
316
|
+
- Having name and description properties
|
|
317
|
+
- Having a url property
|
|
318
|
+
- Having links object with twitter and github links
|
|
319
|
+
- Valid URL formats for url and links
|
|
320
|
+
|
|
321
|
+
### Health Check Tests
|
|
322
|
+
|
|
323
|
+
**File**: [`src/features/__tests__/health-check-types.test.ts`](../../src/features/__tests__/health-check-types.test.ts)
|
|
324
|
+
|
|
325
|
+
Tests health check types:
|
|
326
|
+
- Accepting valid health status values
|
|
327
|
+
- Having exactly 5 valid health status values
|
|
328
|
+
- Creating valid ServiceCheck objects
|
|
329
|
+
- Creating ServiceCheck with and without optional fields
|
|
330
|
+
- Accepting all valid HealthStatus values in ServiceHealth
|
|
331
|
+
|
|
332
|
+
**File**: [`src/features/__tests__/health-check-config.test.ts`](../../src/features/__tests__/health-check-config.test.ts)
|
|
333
|
+
|
|
334
|
+
Tests health check service configuration:
|
|
335
|
+
- Having 6 services configured
|
|
336
|
+
- Having Clerk Authentication, Supabase Database, Supabase Storage, Supabase Edge Functions, Snowflake, and NextBank services
|
|
337
|
+
- Having all services with required properties
|
|
338
|
+
- Having all checks with required properties
|
|
339
|
+
- Having unique service names and icons
|
|
340
|
+
- Having correct endpoints for all checks
|
|
341
|
+
|
|
342
|
+
### Schema Tests
|
|
343
|
+
|
|
344
|
+
**File**: [`src/server/db/schema/__tests__/users.test.ts`](../../src/server/db/schema/__tests__/users.test.ts)
|
|
345
|
+
|
|
346
|
+
Tests the users database schema:
|
|
347
|
+
- Exporting User type
|
|
348
|
+
- Exporting NewUser type
|
|
349
|
+
- Allowing NewUser without optional fields
|
|
350
|
+
|
|
351
|
+
**File**: [`src/server/db/schema/__tests__/health-checks.test.ts`](../../src/server/db/schema/__tests__/health-checks.test.ts)
|
|
352
|
+
|
|
353
|
+
Tests the health checks database schema:
|
|
354
|
+
- Exporting HealthCheckTest type
|
|
355
|
+
- Allowing HealthCheckTest with null testValue
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Test Mocks
|
|
360
|
+
|
|
361
|
+
### Supabase Mock
|
|
362
|
+
|
|
363
|
+
**File**: [`src/test/mocks/supabase.ts`](../../src/test/mocks/supabase.ts)
|
|
364
|
+
|
|
365
|
+
Provides a mock Supabase client with:
|
|
366
|
+
- Database methods (from, select, insert, update, delete, eq, order, limit, single, maybeSingle, rpc)
|
|
367
|
+
- Auth methods (getUser, signInWithPassword, signOut, onAuthStateChange)
|
|
368
|
+
- Storage methods (upload, download, remove, list, getPublicUrl)
|
|
369
|
+
|
|
370
|
+
### Clerk Mock
|
|
371
|
+
|
|
372
|
+
**File**: [`src/test/mocks/clerk.ts`](../../src/test/mocks/clerk.ts)
|
|
373
|
+
|
|
374
|
+
Provides a mock Clerk client with:
|
|
375
|
+
- User methods (getUser, getUserList)
|
|
376
|
+
- Organization methods (getOrganizationMembershipList, getOrganizationList)
|
|
377
|
+
- React components (ClerkProvider, SignedIn, SignedOut, UserButton, SignIn, SignUp)
|
|
378
|
+
- Hooks (useUser, useAuth)
|
|
379
|
+
|
|
380
|
+
### Snowflake Mock
|
|
381
|
+
|
|
382
|
+
**File**: [`src/test/mocks/snowflake.ts`](../../src/test/mocks/snowflake.ts)
|
|
383
|
+
|
|
384
|
+
Provides a mock Snowflake connection with:
|
|
385
|
+
- Connection methods (connect, destroy, isUp, getId)
|
|
386
|
+
- Query execution methods (execute)
|
|
387
|
+
- SDK methods (createConnection, createConnector)
|
|
388
|
+
|
|
389
|
+
### Test Helpers
|
|
390
|
+
|
|
391
|
+
**File**: [`src/test/utils/test-helpers.ts`](../../src/test/utils/test-helpers.ts)
|
|
392
|
+
|
|
393
|
+
Provides utility functions for testing:
|
|
394
|
+
- `renderWithProviders`: Custom render function with providers
|
|
395
|
+
- `mockResolved`: Create a mock function that returns a resolved value
|
|
396
|
+
- `mockRejected`: Create a mock function that returns a rejected value
|
|
397
|
+
- `wait`: Wait for a specified amount of time
|
|
398
|
+
- `createMockUser`: Create a mock user object
|
|
399
|
+
- `createMockHealthCheck`: Create a mock health check result
|
|
400
|
+
- `createMockServiceHealth`: Create a mock service health object
|
|
401
|
+
- `suppressConsoleWarnings`: Mock console methods to suppress warnings
|
|
402
|
+
- `createMockResponse`: Create a mock fetch response
|
|
403
|
+
- `mockLocalStorage`: Mock localStorage
|
|
404
|
+
- `createMockRouter`: Create a mock router
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Testing Best Practices
|
|
409
|
+
|
|
410
|
+
### 1. Test Behavior, Not Implementation
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// ✅ Good - Tests behavior
|
|
414
|
+
it('displays user email', () => {
|
|
415
|
+
render(<UserProfile user={user} />)
|
|
416
|
+
expect(screen.getByText('user@example.com')).toBeInTheDocument()
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
// ❌ Bad - Tests implementation
|
|
420
|
+
it('renders a div with class email', () => {
|
|
421
|
+
render(<UserProfile user={user} />)
|
|
422
|
+
expect(screen.getByRole('div')).toHaveClass('email')
|
|
423
|
+
})
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### 2. Use Descriptive Test Names
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
// ✅ Good - Descriptive
|
|
430
|
+
it('returns 404 when user does not exist', async () => {})
|
|
431
|
+
|
|
432
|
+
// ❌ Bad - Vague
|
|
433
|
+
it('handles missing user', async () => {})
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### 3. Test Edge Cases
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
describe('formatDate', () => {
|
|
440
|
+
it('handles null input', () => {})
|
|
441
|
+
it('handles undefined input', () => {})
|
|
442
|
+
it('handles invalid date', () => {})
|
|
443
|
+
it('handles leap year', () => {})
|
|
444
|
+
})
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### 4. Use beforeEach and afterEach
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
describe('User Queries', () => {
|
|
451
|
+
beforeEach(async () => {
|
|
452
|
+
// Setup test data
|
|
453
|
+
await setupTestData()
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
afterEach(async () => {
|
|
457
|
+
// Cleanup test data
|
|
458
|
+
await cleanupTestData()
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it('fetches user by id', async () => {})
|
|
462
|
+
})
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 5. Mock External Dependencies
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
// Mock external services to avoid making real API calls
|
|
469
|
+
vi.mock('@/lib/snowflake/client')
|
|
470
|
+
vi.mock('@/lib/supabase/admin')
|
|
471
|
+
vi.mock('@/lib/nextbank/client')
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### 6. Keep Tests Isolated
|
|
475
|
+
|
|
476
|
+
Each test should be independent:
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
// ✅ Good - Each test is independent
|
|
480
|
+
it('creates user', async () => {
|
|
481
|
+
const result = await createUser({ email: 'test@example.com' })
|
|
482
|
+
expect(result.email).toBe('test@example.com')
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('creates another user', async () => {
|
|
486
|
+
const result = await createUser({ email: 'another@example.com' })
|
|
487
|
+
expect(result.email).toBe('another@example.com')
|
|
488
|
+
})
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Coverage Goals
|
|
494
|
+
|
|
495
|
+
The framework aims for the following coverage targets:
|
|
496
|
+
|
|
497
|
+
| Metric | Target |
|
|
498
|
+
|--------|--------|
|
|
499
|
+
| Lines | 80% |
|
|
500
|
+
| Functions | 80% |
|
|
501
|
+
| Branches | 80% |
|
|
502
|
+
| Statements | 80% |
|
|
503
|
+
|
|
504
|
+
### Viewing Coverage
|
|
505
|
+
|
|
506
|
+
Run the coverage report:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
pnpm test:coverage
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Troubleshooting
|
|
515
|
+
|
|
516
|
+
### Tests Not Running
|
|
517
|
+
|
|
518
|
+
If tests are not running, check:
|
|
519
|
+
1. Vitest is installed: `pnpm list | grep vitest`
|
|
520
|
+
2. Configuration file exists: `vitest.config.ts`
|
|
521
|
+
3. Test files are in the correct location: `**/__tests__/**/*.{test,spec}.{ts,tsx}`
|
|
522
|
+
|
|
523
|
+
### Mocks Not Working
|
|
524
|
+
|
|
525
|
+
If mocks are not working:
|
|
526
|
+
1. Ensure mocks are defined before importing module
|
|
527
|
+
2. Use `vi.mock()` at the top of the file
|
|
528
|
+
3. Clear mocks in `beforeEach()`: `vi.clearAllMocks()`
|
|
529
|
+
|
|
530
|
+
### Coverage Not Meeting Targets
|
|
531
|
+
|
|
532
|
+
If coverage is below targets:
|
|
533
|
+
1. Identify uncovered code in HTML report
|
|
534
|
+
2. Write tests for uncovered branches
|
|
535
|
+
3. Refactor complex functions to be more testable
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## Related Documentation
|
|
540
|
+
|
|
541
|
+
- [API Layer](./api-layer.md) - API route structure
|
|
542
|
+
- [State Management](./state-management.md) - Testing hooks and stores
|
|
543
|
+
- [Implementation](./implementation.md) - Framework architecture
|
|
544
|
+
- [Environment Variables](./environment-variables.md) - Configuration setup
|