@qazuor/claude-code-config 0.1.0

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.
Files changed (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1248 -0
  3. package/dist/bin.cjs +11886 -0
  4. package/dist/bin.cjs.map +1 -0
  5. package/dist/bin.d.cts +1 -0
  6. package/dist/bin.d.ts +1 -0
  7. package/dist/bin.js +11869 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/index.cjs +3887 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +1325 -0
  12. package/dist/index.d.ts +1325 -0
  13. package/dist/index.js +3835 -0
  14. package/dist/index.js.map +1 -0
  15. package/package.json +86 -0
  16. package/templates/.log/notifications.log +1775 -0
  17. package/templates/agents/README.md +164 -0
  18. package/templates/agents/_registry.json +443 -0
  19. package/templates/agents/design/content-writer.md +353 -0
  20. package/templates/agents/design/ux-ui-designer.md +382 -0
  21. package/templates/agents/engineering/astro-engineer.md +293 -0
  22. package/templates/agents/engineering/db-drizzle-engineer.md +360 -0
  23. package/templates/agents/engineering/express-engineer.md +316 -0
  24. package/templates/agents/engineering/fastify-engineer.md +399 -0
  25. package/templates/agents/engineering/hono-engineer.md +263 -0
  26. package/templates/agents/engineering/mongoose-engineer.md +473 -0
  27. package/templates/agents/engineering/nestjs-engineer.md +429 -0
  28. package/templates/agents/engineering/nextjs-engineer.md +451 -0
  29. package/templates/agents/engineering/node-typescript-engineer.md +347 -0
  30. package/templates/agents/engineering/prisma-engineer.md +432 -0
  31. package/templates/agents/engineering/react-senior-dev.md +394 -0
  32. package/templates/agents/engineering/tanstack-start-engineer.md +447 -0
  33. package/templates/agents/engineering/tech-lead.md +269 -0
  34. package/templates/agents/product/product-functional.md +329 -0
  35. package/templates/agents/product/product-technical.md +578 -0
  36. package/templates/agents/quality/debugger.md +514 -0
  37. package/templates/agents/quality/qa-engineer.md +390 -0
  38. package/templates/agents/specialized/enrichment-agent.md +277 -0
  39. package/templates/agents/specialized/i18n-specialist.md +322 -0
  40. package/templates/agents/specialized/seo-ai-specialist.md +387 -0
  41. package/templates/agents/specialized/tech-writer.md +300 -0
  42. package/templates/code-style/.editorconfig +27 -0
  43. package/templates/code-style/.prettierignore +25 -0
  44. package/templates/code-style/.prettierrc +12 -0
  45. package/templates/code-style/biome.json +78 -0
  46. package/templates/code-style/commitlint.config.js +44 -0
  47. package/templates/commands/README.md +175 -0
  48. package/templates/commands/_registry.json +420 -0
  49. package/templates/commands/add-new-entity.md +211 -0
  50. package/templates/commands/audit/accessibility-audit.md +360 -0
  51. package/templates/commands/audit/performance-audit.md +290 -0
  52. package/templates/commands/audit/security-audit.md +231 -0
  53. package/templates/commands/code-check.md +127 -0
  54. package/templates/commands/five-why.md +225 -0
  55. package/templates/commands/formatting/format-markdown.md +197 -0
  56. package/templates/commands/git/commit.md +247 -0
  57. package/templates/commands/meta/create-agent.md +257 -0
  58. package/templates/commands/meta/create-command.md +312 -0
  59. package/templates/commands/meta/create-skill.md +321 -0
  60. package/templates/commands/meta/help.md +318 -0
  61. package/templates/commands/planning/check-completed-tasks.md +224 -0
  62. package/templates/commands/planning/cleanup-issues.md +248 -0
  63. package/templates/commands/planning/planning-cleanup.md +251 -0
  64. package/templates/commands/planning/sync-planning-github.md +133 -0
  65. package/templates/commands/planning/sync-todos-github.md +203 -0
  66. package/templates/commands/quality-check.md +211 -0
  67. package/templates/commands/run-tests.md +159 -0
  68. package/templates/commands/start-feature-plan.md +232 -0
  69. package/templates/commands/start-refactor-plan.md +244 -0
  70. package/templates/commands/sync-planning.md +176 -0
  71. package/templates/commands/update-docs.md +242 -0
  72. package/templates/docs/CHECKPOINT-SYSTEM.md +504 -0
  73. package/templates/docs/INDEX.md +677 -0
  74. package/templates/docs/RECOMMENDED-HOOKS.md +415 -0
  75. package/templates/docs/_registry.json +329 -0
  76. package/templates/docs/diagrams/README.md +220 -0
  77. package/templates/docs/diagrams/agent-hierarchy.mmd +55 -0
  78. package/templates/docs/diagrams/documentation-map.mmd +61 -0
  79. package/templates/docs/diagrams/tools-relationship.mmd +55 -0
  80. package/templates/docs/diagrams/workflow-decision-tree.mmd +38 -0
  81. package/templates/docs/doc-sync.md +533 -0
  82. package/templates/docs/examples/end-to-end-workflow.md +1505 -0
  83. package/templates/docs/glossary.md +495 -0
  84. package/templates/docs/guides/mockup-prompt-engineering.md +644 -0
  85. package/templates/docs/guides/mockup-setup.md +737 -0
  86. package/templates/docs/learnings/README.md +250 -0
  87. package/templates/docs/learnings/common-architectural-patterns.md +123 -0
  88. package/templates/docs/learnings/common-mistakes-to-avoid.md +149 -0
  89. package/templates/docs/learnings/markdown-formatting-standards.md +104 -0
  90. package/templates/docs/learnings/monorepo-command-execution.md +64 -0
  91. package/templates/docs/learnings/optimization-tips.md +146 -0
  92. package/templates/docs/learnings/planning-linear-sync-workflow.md +70 -0
  93. package/templates/docs/learnings/shell-compatibility-fish.md +46 -0
  94. package/templates/docs/learnings/test-organization-structure.md +68 -0
  95. package/templates/docs/mcp-installation.md +613 -0
  96. package/templates/docs/mcp-servers.md +989 -0
  97. package/templates/docs/notification-installation.md +570 -0
  98. package/templates/docs/quick-start.md +354 -0
  99. package/templates/docs/standards/architecture-patterns.md +1064 -0
  100. package/templates/docs/standards/atomic-commits.md +513 -0
  101. package/templates/docs/standards/code-standards.md +993 -0
  102. package/templates/docs/standards/design-standards.md +656 -0
  103. package/templates/docs/standards/documentation-standards.md +1160 -0
  104. package/templates/docs/standards/testing-standards.md +969 -0
  105. package/templates/docs/system-maintenance.md +604 -0
  106. package/templates/docs/templates/PDR-template.md +561 -0
  107. package/templates/docs/templates/TODOs-template.md +534 -0
  108. package/templates/docs/templates/tech-analysis-template.md +800 -0
  109. package/templates/docs/workflows/README.md +519 -0
  110. package/templates/docs/workflows/atomic-task-protocol.md +955 -0
  111. package/templates/docs/workflows/decision-tree.md +482 -0
  112. package/templates/docs/workflows/edge-cases.md +856 -0
  113. package/templates/docs/workflows/phase-1-planning.md +957 -0
  114. package/templates/docs/workflows/phase-2-implementation.md +896 -0
  115. package/templates/docs/workflows/phase-3-validation.md +792 -0
  116. package/templates/docs/workflows/phase-4-finalization.md +927 -0
  117. package/templates/docs/workflows/quick-fix-protocol.md +505 -0
  118. package/templates/docs/workflows/task-atomization.md +537 -0
  119. package/templates/docs/workflows/task-completion-protocol.md +448 -0
  120. package/templates/hooks/on-notification.sh +28 -0
  121. package/templates/schemas/checkpoint.schema.json +97 -0
  122. package/templates/schemas/code-registry.schema.json +84 -0
  123. package/templates/schemas/pdr.schema.json +314 -0
  124. package/templates/schemas/problems.schema.json +55 -0
  125. package/templates/schemas/tech-analysis.schema.json +404 -0
  126. package/templates/schemas/telemetry.schema.json +298 -0
  127. package/templates/schemas/todos.schema.json +234 -0
  128. package/templates/schemas/workflows.schema.json +69 -0
  129. package/templates/scripts/add-changelogs.sh +105 -0
  130. package/templates/scripts/generate-code-registry.ts +270 -0
  131. package/templates/scripts/health-check.sh +343 -0
  132. package/templates/scripts/sync-registry.sh +40 -0
  133. package/templates/scripts/telemetry-report.ts +36 -0
  134. package/templates/scripts/validate-docs.sh +224 -0
  135. package/templates/scripts/validate-registry.sh +225 -0
  136. package/templates/scripts/validate-schemas.ts +283 -0
  137. package/templates/scripts/validate-structure.sh +165 -0
  138. package/templates/scripts/worktree-cleanup.sh +81 -0
  139. package/templates/scripts/worktree-create.sh +63 -0
  140. package/templates/sessions/planning/.gitkeep +0 -0
  141. package/templates/sessions/planning/archived/.gitkeep +0 -0
  142. package/templates/settings.json +202 -0
  143. package/templates/settings.local.json +138 -0
  144. package/templates/skills/README.md +197 -0
  145. package/templates/skills/_registry.json +473 -0
  146. package/templates/skills/audit/accessibility-audit.md +309 -0
  147. package/templates/skills/audit/performance-audit.md +257 -0
  148. package/templates/skills/audit/security-audit.md +217 -0
  149. package/templates/skills/auth/nextauth-patterns.md +308 -0
  150. package/templates/skills/brand-guidelines.md +240 -0
  151. package/templates/skills/documentation/markdown-formatter.md +302 -0
  152. package/templates/skills/git/git-commit-helper.md +321 -0
  153. package/templates/skills/i18n/i18n-patterns.md +251 -0
  154. package/templates/skills/patterns/error-handling-patterns.md +242 -0
  155. package/templates/skills/patterns/tdd-methodology.md +342 -0
  156. package/templates/skills/qa/qa-criteria-validator.md +383 -0
  157. package/templates/skills/qa/web-app-testing.md +398 -0
  158. package/templates/skills/react/react-hook-form-patterns.md +359 -0
  159. package/templates/skills/state/redux-toolkit-patterns.md +272 -0
  160. package/templates/skills/state/tanstack-query-patterns.md +299 -0
  161. package/templates/skills/state/zustand-patterns.md +301 -0
  162. package/templates/skills/tech/mermaid-diagram-specialist.md +195 -0
  163. package/templates/skills/tech/shadcn-specialist.md +252 -0
  164. package/templates/skills/tech/vercel-specialist.md +297 -0
  165. package/templates/skills/testing/api-app-testing.md +254 -0
  166. package/templates/skills/testing/performance-testing.md +275 -0
  167. package/templates/skills/testing/security-testing.md +348 -0
  168. package/templates/skills/utils/add-memory.md +295 -0
  169. package/templates/skills/utils/json-data-auditor.md +283 -0
  170. package/templates/skills/utils/pdf-creator-editor.md +342 -0
  171. package/templates/tools/format-markdown.sh +185 -0
@@ -0,0 +1,969 @@
1
+ # Testing Standards
2
+
3
+ This document defines the testing standards and practices.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ <!-- markdownlint-disable MD051 -->
10
+
11
+ 1. [Testing Philosophy](#testing-philosophy)
12
+ 2. [TDD Workflow](#tdd-workflow)
13
+ 3. [Test Types](#test-types)
14
+ 4. [Coverage Requirements](#coverage-requirements)
15
+ 5. [Test Structure](#test-structure)
16
+ 6. [Naming Conventions](#naming-conventions)
17
+ 7. [Test Patterns](#test-patterns)
18
+ 8. [Mocking & Fixtures](#mocking--fixtures)
19
+ 9. [Database Testing](#database-testing)
20
+ 10. [API Testing](#api-testing)
21
+ 11. [Frontend Testing](#frontend-testing)
22
+ 12. [Common Pitfalls](#common-pitfalls)
23
+
24
+ <!-- markdownlint-enable MD051 -->
25
+
26
+ ---
27
+
28
+ ## Testing Philosophy
29
+
30
+ ### Core Principles
31
+
32
+ **Test-Driven Development (TDD):**
33
+
34
+ - Write tests FIRST, before implementation
35
+ - Follow Red → Green → Refactor cycle
36
+ - Tests define the interface and behavior
37
+
38
+ **90% Minimum Coverage:**
39
+
40
+ - Unit tests: All public functions
41
+ - Integration tests: All API endpoints
42
+ - E2E tests: Critical user flows
43
+
44
+ **Test Quality Over Quantity:**
45
+
46
+ - Tests should be maintainable
47
+ - Tests should be readable
48
+ - Tests should test behavior, not implementation
49
+
50
+ ---
51
+
52
+ ## TDD Workflow
53
+
54
+ ### Red → Green → Refactor
55
+
56
+ ```text
57
+
58
+ 1. RED: Write a failing test
59
+ - Define what you want to build
60
+ - Test should fail (no implementation yet)
61
+
62
+ 2. GREEN: Write minimum code to pass
63
+ - Implement just enough to make test pass
64
+ - Don't worry about perfection yet
65
+
66
+ 3. REFACTOR: Improve the code
67
+ - Clean up implementation
68
+ - Tests stay green
69
+ - Improve design
70
+
71
+ ```text
72
+
73
+ ### Example TDD Cycle
74
+
75
+ ```typescript
76
+ // 1. RED: Write failing test
77
+ describe('UserService', () => {
78
+ it('should create user with valid data', async () => {
79
+ const input = {
80
+ name: 'John Doe',
81
+ email: 'john@example.com',
82
+ role: 'host' as const,
83
+ };
84
+
85
+ const result = await userService.create({ input, user: adminUser });
86
+
87
+ expect(result.user).toBeDefined();
88
+ expect(result.user.email).toBe('john@example.com');
89
+ });
90
+ });
91
+
92
+ // 2. GREEN: Implement minimum code
93
+ async create({ input, user }) {
94
+ const newUser = await this.model.create(input);
95
+ return { user: newUser };
96
+ }
97
+
98
+ // 3. REFACTOR: Add validation, error handling, etc.
99
+ async create({ input, user }) {
100
+ // Validate input
101
+ if (!input.email.includes('@')) {
102
+ throw new ServiceError('Invalid email', ServiceErrorCode.VALIDATION_ERROR);
103
+ }
104
+
105
+ // Check permissions
106
+ if (user.role !== 'admin') {
107
+ throw new ServiceError('Forbidden', ServiceErrorCode.FORBIDDEN);
108
+ }
109
+
110
+ // Create user
111
+ const newUser = await this.model.create(input);
112
+
113
+ return { user: newUser };
114
+ }
115
+ ```text
116
+
117
+ ---
118
+
119
+ ## Test Types
120
+
121
+ ### Unit Tests
122
+
123
+ **Purpose:** Test individual functions/methods in isolation
124
+
125
+ **Characteristics:**
126
+
127
+ - Fast (< 1ms per test)
128
+ - No external dependencies
129
+ - Mock all dependencies
130
+ - Test single responsibility
131
+
132
+ **Example:**
133
+
134
+ ```typescript
135
+ describe('calculateBookingPrice', () => {
136
+ it('should calculate price for 3 nights', () => {
137
+ const input = {
138
+ pricePerNight: 100,
139
+ nights: 3,
140
+ };
141
+
142
+ const result = calculateBookingPrice(input);
143
+
144
+ expect(result.totalPrice).toBe(300);
145
+ });
146
+
147
+ it('should apply discount for 7+ nights', () => {
148
+ const input = {
149
+ pricePerNight: 100,
150
+ nights: 7,
151
+ };
152
+
153
+ const result = calculateBookingPrice(input);
154
+
155
+ expect(result.totalPrice).toBe(630); // 10% discount
156
+ expect(result.discount).toBe(70);
157
+ });
158
+ });
159
+ ```text
160
+
161
+ ### Integration Tests
162
+
163
+ **Purpose:** Test interaction between components
164
+
165
+ **Characteristics:**
166
+
167
+ - Moderate speed (< 100ms per test)
168
+ - Real database (test database)
169
+ - Real services
170
+ - Mock only external APIs
171
+
172
+ **Example:**
173
+
174
+ ```typescript
175
+ describe('EntityService Integration', () => {
176
+ let service: EntityService;
177
+ let testDb: Database;
178
+
179
+ beforeEach(async () => {
180
+ testDb = await createTestDatabase();
181
+ service = new EntityService({ db: testDb });
182
+ });
183
+
184
+ afterEach(async () => {
185
+ await testDb.destroy();
186
+ });
187
+
188
+ it('should create entity and retrieve it', async () => {
189
+ // Arrange
190
+ const input = {
191
+ name: 'Beach House',
192
+ type: 'house' as const,
193
+ capacity: 6,
194
+ pricePerNight: 150,
195
+ };
196
+
197
+ // Act - Create
198
+ const created = await service.create({ input, user: hostUser });
199
+
200
+ // Act - Retrieve
201
+ const retrieved = await service.findById({ id: created.entity.id });
202
+
203
+ // Assert
204
+ expect(retrieved.entity.name).toBe('Beach House');
205
+ expect(retrieved.entity.capacity).toBe(6);
206
+ });
207
+ });
208
+ ```text
209
+
210
+ ### E2E Tests
211
+
212
+ **Purpose:** Test complete user flows
213
+
214
+ **Characteristics:**
215
+
216
+ - Slow (1-5 seconds per test)
217
+ - Real browser (Playwright/Cypress)
218
+ - Real API calls
219
+ - Test from user perspective
220
+
221
+ **Example:**
222
+
223
+ ```typescript
224
+ describe('Booking Flow', () => {
225
+ it('should allow user to search, view, and book entity', async () => {
226
+ // 1. Navigate to search
227
+ await page.goto('/entitys');
228
+
229
+ // 2. Search for entity
230
+ await page.fill('[name="search"]', 'Beach House');
231
+ await page.click('button[type="submit"]');
232
+
233
+ // 3. View details
234
+ await page.click('text=Beach House');
235
+ expect(page.url()).toContain('/entitys/');
236
+
237
+ // 4. Select dates
238
+ await page.fill('[name="checkIn"]', '2024-07-01');
239
+ await page.fill('[name="checkOut"]', '2024-07-05');
240
+
241
+ // 5. Book
242
+ await page.click('text=Book Now');
243
+
244
+ // 6. Verify confirmation
245
+ await expect(page.locator('text=Booking Confirmed')).toBeVisible();
246
+ });
247
+ });
248
+ ```text
249
+
250
+ ---
251
+
252
+ ## Coverage Requirements
253
+
254
+ ### Minimum Coverage: 90%
255
+
256
+ **What to test:**
257
+
258
+ - All public functions/methods
259
+ - All API endpoints
260
+ - All business logic paths
261
+ - All error cases
262
+ - All edge cases
263
+
264
+ **What NOT to test:**
265
+
266
+ - Private functions (test through public API)
267
+ - Type definitions
268
+ - Third-party libraries
269
+ - Constants
270
+
271
+ ### Coverage by Layer
272
+
273
+ | Layer | Unit | Integration | E2E |
274
+ |-------|------|-------------|-----|
275
+ | Models | ✅ All methods | ✅ Database operations | ❌ |
276
+ | Services | ✅ All methods | ✅ With database | ❌ |
277
+ | API Routes | ✅ Logic | ✅ Endpoints | ✅ Critical flows |
278
+ | Components | ✅ Logic | ✅ User interactions | ✅ Main flows |
279
+
280
+ ---
281
+
282
+ ## Test Structure
283
+
284
+ ### AAA Pattern (Arrange, Act, Assert)
285
+
286
+ **Always use AAA structure:**
287
+
288
+ ```typescript
289
+ it('should create user with valid data', async () => {
290
+ // ARRANGE: Setup test data and dependencies
291
+ const input = {
292
+ name: 'John Doe',
293
+ email: 'john@example.com',
294
+ role: 'host' as const,
295
+ };
296
+ const mockUser = createTestUser({ role: 'admin' });
297
+
298
+ // ACT: Execute the function being tested
299
+ const result = await userService.create({ input, user: mockUser });
300
+
301
+ // ASSERT: Verify the result
302
+ expect(result.user).toBeDefined();
303
+ expect(result.user.name).toBe('John Doe');
304
+ expect(result.user.email).toBe('john@example.com');
305
+ });
306
+ ```text
307
+
308
+ ### Given-When-Then (for Acceptance Tests)
309
+
310
+ ```typescript
311
+ it('Given user is admin, When creating user, Then user is created', async () => {
312
+ // GIVEN: Setup preconditions
313
+ const adminUser = createTestUser({ role: 'admin' });
314
+ const inputData = createTestUserInput();
315
+
316
+ // WHEN: Perform action
317
+ const result = await userService.create({ input: inputData, user: adminUser });
318
+
319
+ // THEN: Verify outcome
320
+ expect(result.user.id).toBeDefined();
321
+ expect(result.user.role).toBe('host');
322
+ });
323
+ ```text
324
+
325
+ ---
326
+
327
+ ## Test File Organization
328
+
329
+ ### Test Folder Structure
330
+
331
+ **Rule:** All tests MUST be placed in a `test/` folder at the root of each package/app, mirroring the source folder structure.
332
+
333
+ **Structure:**
334
+
335
+ ```text
336
+ packages/my-package/
337
+ ├── src/
338
+ │ ├── services/
339
+ │ │ └── user-service.ts
340
+ │ ├── utils/
341
+ │ │ └── validators.ts
342
+ │ └── index.ts
343
+ └── test/
344
+ ├── services/
345
+ │ └── user-service.test.ts
346
+ ├── utils/
347
+ │ └── validators.test.ts
348
+ └── index.test.ts
349
+ ```
350
+
351
+ **Examples:**
352
+
353
+ ```text
354
+ ✅ CORRECT:
355
+ Source: packages/db/src/models/user.model.ts
356
+ Test: packages/db/test/models/user.model.test.ts
357
+
358
+ Source: packages/service-core/src/services/booking/booking-service.ts
359
+ Test: packages/service-core/test/services/booking/booking-service.test.ts
360
+
361
+ Source: apps/api/src/routes/entitys.ts
362
+ Test: apps/api/test/routes/entitys.test.ts
363
+
364
+ ❌ INCORRECT:
365
+ Source: packages/db/src/models/user.model.ts
366
+ Test: packages/db/src/models/user.model.test.ts (tests should NOT be in src/)
367
+
368
+ Source: packages/db/src/models/user.model.ts
369
+ Test: packages/db/test/user.model.test.ts (missing models/ folder)
370
+ ```
371
+
372
+ ### Import Paths in Tests
373
+
374
+ When importing from source files, use relative paths from test/ to src/:
375
+
376
+ ```typescript
377
+ // ✅ CORRECT: test/services/user-service.test.ts
378
+ import { UserService } from '../src/services/user-service.js';
379
+
380
+ // ✅ CORRECT: test/models/user.model.test.ts
381
+ import { UserModel } from '../src/models/user.model.js';
382
+
383
+ // ❌ INCORRECT: Don't use same-folder imports
384
+ import { UserService } from './user-service.js';
385
+ ```
386
+
387
+ ### Vitest Configuration
388
+
389
+ Vitest automatically discovers tests in `test/` folders. No special configuration needed:
390
+
391
+ ```typescript
392
+ // vitest.config.ts
393
+ export default defineConfig({
394
+ test: {
395
+ globals: true,
396
+ environment: 'node',
397
+ coverage: {
398
+ provider: 'v8',
399
+ exclude: [
400
+ 'node_modules/',
401
+ 'dist/',
402
+ '**/*.test.ts', // Excludes tests wherever they are
403
+ '**/*.config.ts',
404
+ ],
405
+ },
406
+ },
407
+ });
408
+ ```
409
+
410
+ ---
411
+
412
+ ## Naming Conventions
413
+
414
+ ### Test File Names
415
+
416
+ ```text
417
+ {module-name}.test.ts
418
+ {module-name}.integration.test.ts
419
+ {module-name}.e2e.test.ts
420
+ ```
421
+
422
+ **Examples:**
423
+
424
+ ```text
425
+ user-service.test.ts
426
+ user-service.integration.test.ts
427
+ booking-flow.e2e.test.ts
428
+ ```
429
+
430
+ ### Test Description
431
+
432
+ ```typescript
433
+ // ✅ GOOD: Descriptive, behavior-focused
434
+ describe('UserService', () => {
435
+ describe('create', () => {
436
+ it('should create user with valid data', async () => {});
437
+ it('should throw error when email already exists', async () => {});
438
+ it('should throw error when user lacks permissions', async () => {});
439
+ });
440
+ });
441
+
442
+ // ❌ BAD: Implementation-focused
443
+ describe('UserService', () => {
444
+ it('test create', async () => {});
445
+ it('test validation', async () => {});
446
+ });
447
+ ```text
448
+
449
+ ### Variable Names
450
+
451
+ ```typescript
452
+ // ✅ GOOD: Clear, descriptive names
453
+ const inputValid = { name: 'John', email: 'john@example.com' };
454
+ const inputInvalid = { name: '', email: 'invalid' };
455
+ const mockUser = createTestUser();
456
+ const expectedResult = { id: '123', name: 'John' };
457
+ const actualResult = await service.create({ input: inputValid, user: mockUser });
458
+
459
+ // ❌ BAD: Unclear names
460
+ const data = { name: 'John' };
461
+ const result = await service.create({ input: data });
462
+ ```text
463
+
464
+ ---
465
+
466
+ ## Test Patterns
467
+
468
+ ### Setup and Teardown
469
+
470
+ ```typescript
471
+ describe('UserService', () => {
472
+ let service: UserService;
473
+ let db: Database;
474
+ let testUser: User;
475
+
476
+ // Run before all tests in this suite
477
+ beforeAll(async () => {
478
+ db = await createTestDatabase();
479
+ });
480
+
481
+ // Run before each test
482
+ beforeEach(async () => {
483
+ service = new UserService({ db });
484
+ testUser = await createTestUser();
485
+ });
486
+
487
+ // Run after each test
488
+ afterEach(async () => {
489
+ await cleanupTestData();
490
+ });
491
+
492
+ // Run after all tests
493
+ afterAll(async () => {
494
+ await db.destroy();
495
+ });
496
+
497
+ it('should work', async () => {
498
+ // Test has access to service, db, testUser
499
+ });
500
+ });
501
+ ```text
502
+
503
+ ### Parameterized Tests
504
+
505
+ ```typescript
506
+ describe('validateEmail', () => {
507
+ const testCases = [
508
+ { email: 'valid@example.com', expected: true },
509
+ { email: 'invalid', expected: false },
510
+ { email: 'missing@domain', expected: false },
511
+ { email: '@example.com', expected: false },
512
+ ];
513
+
514
+ testCases.forEach(({ email, expected }) => {
515
+ it(`should return ${expected} for "${email}"`, () => {
516
+ const result = validateEmail(email);
517
+ expect(result).toBe(expected);
518
+ });
519
+ });
520
+ });
521
+ ```text
522
+
523
+ ### Testing Errors
524
+
525
+ ```typescript
526
+ describe('UserService', () => {
527
+ it('should throw NOT_FOUND when user does not exist', async () => {
528
+ await expect(
529
+ service.findById({ id: 'non-existent-id' })
530
+ ).rejects.toThrow(ServiceError);
531
+
532
+ await expect(
533
+ service.findById({ id: 'non-existent-id' })
534
+ ).rejects.toMatchObject({
535
+ code: ServiceErrorCode.NOT_FOUND,
536
+ message: expect.stringContaining('not found'),
537
+ });
538
+ });
539
+
540
+ it('should throw FORBIDDEN when user lacks permissions', async () => {
541
+ const guestUser = createTestUser({ role: 'guest' });
542
+
543
+ await expect(
544
+ service.create({ input: validInput, user: guestUser })
545
+ ).rejects.toThrow('Forbidden');
546
+ });
547
+ });
548
+ ```text
549
+
550
+ ### Testing Async Code
551
+
552
+ ```typescript
553
+ // ✅ GOOD: Using async/await
554
+ it('should fetch user data', async () => {
555
+ const result = await fetchUser('123');
556
+ expect(result.name).toBe('John');
557
+ });
558
+
559
+ // ✅ GOOD: Using resolves/rejects
560
+ it('should fetch user data', () => {
561
+ return expect(fetchUser('123')).resolves.toMatchObject({
562
+ name: 'John',
563
+ });
564
+ });
565
+
566
+ // ❌ BAD: Not handling async
567
+ it('should fetch user data', () => {
568
+ fetchUser('123'); // Test will pass before promise resolves!
569
+ expect(result.name).toBe('John'); // result is undefined
570
+ });
571
+ ```text
572
+
573
+ ---
574
+
575
+ ## Mocking & Fixtures
576
+
577
+ ### Mock External Dependencies
578
+
579
+ ```typescript
580
+ import { vi } from 'vitest';
581
+
582
+ describe('BookingService', () => {
583
+ let emailService: EmailService;
584
+
585
+ beforeEach(() => {
586
+ // Mock email service
587
+ emailService = {
588
+ sendConfirmation: vi.fn(),
589
+ } as unknown as EmailService;
590
+ });
591
+
592
+ it('should send confirmation email after booking', async () => {
593
+ const service = new BookingService({ db, emailService });
594
+
595
+ await service.create({ input: bookingData, user });
596
+
597
+ expect(emailService.sendConfirmation).toHaveBeenCalledWith({
598
+ to: user.email,
599
+ booking: expect.objectContaining({ id: expect.any(String) }),
600
+ });
601
+ });
602
+ });
603
+ ```text
604
+
605
+ ### Test Fixtures
606
+
607
+ ```typescript
608
+ // test/fixtures/user.fixture.ts
609
+
610
+ export const createTestUser = (overrides?: Partial<User>): User => ({
611
+ id: randomUUID(),
612
+ name: 'Test User',
613
+ email: 'test@example.com',
614
+ role: 'host',
615
+ createdAt: new Date(),
616
+ updatedAt: new Date(),
617
+ deletedAt: null,
618
+ ...overrides,
619
+ });
620
+
621
+ export const createTestAdmin = (): User =>
622
+ createTestUser({ role: 'admin', email: 'admin@example.com' });
623
+
624
+ export const createTestGuest = (): User =>
625
+ createTestUser({ role: 'guest', email: 'guest@example.com' });
626
+ ```text
627
+
628
+ ### Factory Pattern
629
+
630
+ ```typescript
631
+ // test/factories/entity.factory.ts
632
+
633
+ let counter = 0;
634
+
635
+ export const buildEntity = (
636
+ overrides?: Partial<Entity>
637
+ ): Entity => {
638
+ counter++;
639
+ return {
640
+ id: randomUUID(),
641
+ name: `Test Entity ${counter}`,
642
+ type: 'house',
643
+ capacity: 4,
644
+ pricePerNight: 100,
645
+ hostId: randomUUID(),
646
+ createdAt: new Date(),
647
+ updatedAt: new Date(),
648
+ deletedAt: null,
649
+ ...overrides,
650
+ };
651
+ };
652
+ ```text
653
+
654
+ ---
655
+
656
+ ## Database Testing
657
+
658
+ ### Use Test Database
659
+
660
+ ```typescript
661
+ // test/setup.ts
662
+
663
+ let testDb: Database;
664
+
665
+ export const setupTestDatabase = async () => {
666
+ testDb = await createConnection({
667
+ host: 'localhost',
668
+ port: 5433, // Different port for test DB
669
+ database: 'project_test',
670
+ });
671
+
672
+ // Run migrations
673
+ await migrate(testDb);
674
+
675
+ return testDb;
676
+ };
677
+
678
+ export const teardownTestDatabase = async () => {
679
+ await testDb.destroy();
680
+ };
681
+ ```text
682
+
683
+ ### Clean Between Tests
684
+
685
+ ```typescript
686
+ beforeEach(async () => {
687
+ // Clean all tables
688
+ await db.delete(bookings);
689
+ await db.delete(entitys);
690
+ await db.delete(users);
691
+ });
692
+ ```text
693
+
694
+ ### Transaction Rollback Pattern
695
+
696
+ ```typescript
697
+ describe('UserService', () => {
698
+ let trx: Transaction;
699
+
700
+ beforeEach(async () => {
701
+ trx = await db.transaction();
702
+ });
703
+
704
+ afterEach(async () => {
705
+ await trx.rollback(); // Rollback all changes
706
+ });
707
+
708
+ it('should create user', async () => {
709
+ const service = new UserService({ db: trx });
710
+ // Test...
711
+ // Changes are rolled back after test
712
+ });
713
+ });
714
+ ```text
715
+
716
+ ---
717
+
718
+ ## API Testing
719
+
720
+ ### Test API Endpoints
721
+
722
+ ```typescript
723
+ import { app } from '../src/app';
724
+
725
+ describe('POST /api/entitys', () => {
726
+ it('should create entity with valid data', async () => {
727
+ const input = {
728
+ name: 'Beach House',
729
+ type: 'house',
730
+ capacity: 6,
731
+ pricePerNight: 150,
732
+ };
733
+
734
+ const response = await app.request('/api/entitys', {
735
+ method: 'POST',
736
+ body: JSON.stringify(input),
737
+ headers: {
738
+ 'Content-Type': 'application/json',
739
+ 'Authorization': `Bearer ${hostToken}`,
740
+ },
741
+ });
742
+
743
+ expect(response.status).toBe(201);
744
+
745
+ const body = await response.json();
746
+ expect(body.success).toBe(true);
747
+ expect(body.data.entity.name).toBe('Beach House');
748
+ });
749
+
750
+ it('should return 401 when not authenticated', async () => {
751
+ const response = await app.request('/api/entitys', {
752
+ method: 'POST',
753
+ body: JSON.stringify({}),
754
+ });
755
+
756
+ expect(response.status).toBe(401);
757
+ });
758
+
759
+ it('should return 400 when validation fails', async () => {
760
+ const invalidInput = {
761
+ name: '', // Empty name
762
+ type: 'invalid-type',
763
+ };
764
+
765
+ const response = await app.request('/api/entitys', {
766
+ method: 'POST',
767
+ body: JSON.stringify(invalidInput),
768
+ headers: {
769
+ 'Authorization': `Bearer ${hostToken}`,
770
+ },
771
+ });
772
+
773
+ expect(response.status).toBe(400);
774
+ const body = await response.json();
775
+ expect(body.success).toBe(false);
776
+ });
777
+ });
778
+ ```text
779
+
780
+ ---
781
+
782
+ ## Frontend Testing
783
+
784
+ ### Component Testing
785
+
786
+ ```typescript
787
+ import { render, screen, fireEvent } from '@testing-library/react';
788
+ import { EntityCard } from './EntityCard';
789
+
790
+ describe('EntityCard', () => {
791
+ const mockEntity = {
792
+ id: '123',
793
+ name: 'Beach House',
794
+ type: 'house',
795
+ capacity: 6,
796
+ pricePerNight: 150,
797
+ };
798
+
799
+ it('should render entity details', () => {
800
+ render(<EntityCard entity={mockEntity} />);
801
+
802
+ expect(screen.getByText('Beach House')).toBeInTheDocument();
803
+ expect(screen.getByText('$150 / night')).toBeInTheDocument();
804
+ expect(screen.getByText('6 guests')).toBeInTheDocument();
805
+ });
806
+
807
+ it('should call onSelect when clicked', () => {
808
+ const mockOnSelect = vi.fn();
809
+
810
+ render(
811
+ <EntityCard
812
+ entity={mockEntity}
813
+ onSelect={mockOnSelect}
814
+ />
815
+ );
816
+
817
+ fireEvent.click(screen.getByRole('button'));
818
+
819
+ expect(mockOnSelect).toHaveBeenCalledWith('123');
820
+ });
821
+ });
822
+ ```text
823
+
824
+ ### Testing with TanStack Query
825
+
826
+ ```typescript
827
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
828
+ import { renderHook, waitFor } from '@testing-library/react';
829
+ import { useEntitys } from './useEntitys';
830
+
831
+ describe('useEntitys', () => {
832
+ let queryClient: QueryClient;
833
+
834
+ beforeEach(() => {
835
+ queryClient = new QueryClient({
836
+ defaultOptions: {
837
+ queries: { retry: false },
838
+ },
839
+ });
840
+ });
841
+
842
+ it('should fetch entitys', async () => {
843
+ const wrapper = ({ children }) => (
844
+ <QueryClientProvider client={queryClient}>
845
+ {children}
846
+ </QueryClientProvider>
847
+ );
848
+
849
+ const { result } = renderHook(() => useEntitys(), { wrapper });
850
+
851
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
852
+
853
+ expect(result.current.data).toHaveLength(3);
854
+ });
855
+ });
856
+ ```text
857
+
858
+ ---
859
+
860
+ ## Common Pitfalls
861
+
862
+ ### ❌ Testing Implementation Details
863
+
864
+ ```typescript
865
+ // ❌ BAD: Testing private methods
866
+ it('should call _validateEmail internally', () => {
867
+ const spy = vi.spyOn(service, '_validateEmail');
868
+ service.create({ input });
869
+ expect(spy).toHaveBeenCalled();
870
+ });
871
+
872
+ // ✅ GOOD: Testing behavior
873
+ it('should reject invalid email', async () => {
874
+ await expect(
875
+ service.create({ input: { email: 'invalid' } })
876
+ ).rejects.toThrow('Invalid email');
877
+ });
878
+ ```text
879
+
880
+ ### ❌ Brittle Tests
881
+
882
+ ```typescript
883
+ // ❌ BAD: Too specific, will break on small changes
884
+ expect(result).toEqual({
885
+ id: '123',
886
+ name: 'John',
887
+ email: 'john@example.com',
888
+ createdAt: new Date('2024-01-01'),
889
+ updatedAt: new Date('2024-01-01'),
890
+ });
891
+
892
+ // ✅ GOOD: Focus on important parts
893
+ expect(result).toMatchObject({
894
+ name: 'John',
895
+ email: 'john@example.com',
896
+ });
897
+ expect(result.id).toBeDefined();
898
+ expect(result.createdAt).toBeInstanceOf(Date);
899
+ ```text
900
+
901
+ ### ❌ Shared State
902
+
903
+ ```typescript
904
+ // ❌ BAD: Tests affect each other
905
+ let user;
906
+
907
+ beforeAll(() => {
908
+ user = createTestUser();
909
+ });
910
+
911
+ it('test 1', () => {
912
+ user.name = 'Changed'; // Affects other tests!
913
+ });
914
+
915
+ // ✅ GOOD: Fresh state per test
916
+ beforeEach(() => {
917
+ user = createTestUser();
918
+ });
919
+ ```text
920
+
921
+ ### ❌ Not Testing Edge Cases
922
+
923
+ ```typescript
924
+ // ❌ BAD: Only happy path
925
+ it('should calculate price', () => {
926
+ expect(calculatePrice(100, 3)).toBe(300);
927
+ });
928
+
929
+ // ✅ GOOD: Test edge cases
930
+ describe('calculatePrice', () => {
931
+ it('should calculate price for positive values', () => {
932
+ expect(calculatePrice(100, 3)).toBe(300);
933
+ });
934
+
935
+ it('should throw for zero nights', () => {
936
+ expect(() => calculatePrice(100, 0)).toThrow();
937
+ });
938
+
939
+ it('should throw for negative nights', () => {
940
+ expect(() => calculatePrice(100, -1)).toThrow();
941
+ });
942
+
943
+ it('should handle large numbers', () => {
944
+ expect(calculatePrice(1000000, 365)).toBe(365000000);
945
+ });
946
+ });
947
+ ```text
948
+
949
+ ---
950
+
951
+ ## Summary Checklist
952
+
953
+ Before considering testing complete:
954
+
955
+ - [ ] 90%+ code coverage
956
+ - [ ] All public functions tested
957
+ - [ ] All API endpoints tested
958
+ - [ ] All error cases tested
959
+ - [ ] All edge cases tested
960
+ - [ ] Tests follow AAA pattern
961
+ - [ ] Tests are independent
962
+ - [ ] Tests are fast (< 100ms unit, < 1s integration)
963
+ - [ ] No flaky tests
964
+ - [ ] Tests document behavior
965
+
966
+ ---
967
+
968
+ **TDD is mandatory. Tests must be written BEFORE implementation.**
969
+