@massu/core 0.5.0 → 0.6.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 (118) hide show
  1. package/README.md +40 -0
  2. package/agents/massu-architecture-reviewer.md +104 -0
  3. package/agents/massu-blast-radius-analyzer.md +84 -0
  4. package/agents/massu-competitive-scorer.md +126 -0
  5. package/agents/massu-help-sync.md +73 -0
  6. package/agents/massu-migration-writer.md +94 -0
  7. package/agents/massu-output-scorer.md +87 -0
  8. package/agents/massu-pattern-reviewer.md +84 -0
  9. package/agents/massu-plan-auditor.md +170 -0
  10. package/agents/massu-schema-sync-verifier.md +70 -0
  11. package/agents/massu-security-reviewer.md +98 -0
  12. package/agents/massu-ux-reviewer.md +106 -0
  13. package/commands/_shared-preamble.md +53 -23
  14. package/commands/_shared-references/auto-learning-protocol.md +71 -0
  15. package/commands/_shared-references/blast-radius-protocol.md +76 -0
  16. package/commands/_shared-references/security-pre-screen.md +64 -0
  17. package/commands/_shared-references/test-first-protocol.md +87 -0
  18. package/commands/_shared-references/verification-table.md +52 -0
  19. package/commands/massu-article-review.md +343 -0
  20. package/commands/massu-autoresearch/references/eval-runner.md +84 -0
  21. package/commands/massu-autoresearch/references/safety-rails.md +125 -0
  22. package/commands/massu-autoresearch/references/scoring-protocol.md +151 -0
  23. package/commands/massu-autoresearch.md +258 -0
  24. package/commands/massu-batch.md +44 -12
  25. package/commands/massu-bearings.md +42 -8
  26. package/commands/massu-checkpoint.md +588 -0
  27. package/commands/massu-ci-fix.md +2 -2
  28. package/commands/massu-command-health.md +132 -0
  29. package/commands/massu-command-improve.md +232 -0
  30. package/commands/massu-commit.md +205 -44
  31. package/commands/massu-create-plan.md +239 -57
  32. package/commands/massu-data/references/common-queries.md +79 -0
  33. package/commands/massu-data/references/table-guide.md +50 -0
  34. package/commands/massu-data.md +66 -0
  35. package/commands/massu-dead-code.md +29 -34
  36. package/commands/massu-debug/references/auto-learning.md +61 -0
  37. package/commands/massu-debug/references/codegraph-tracing.md +80 -0
  38. package/commands/massu-debug/references/common-shortcuts.md +98 -0
  39. package/commands/massu-debug/references/investigation-phases.md +294 -0
  40. package/commands/massu-debug/references/report-format.md +107 -0
  41. package/commands/massu-debug.md +105 -386
  42. package/commands/massu-docs.md +1 -1
  43. package/commands/massu-full-audit.md +61 -0
  44. package/commands/massu-gap-enhancement-analyzer.md +276 -16
  45. package/commands/massu-golden-path/references/approval-points.md +216 -0
  46. package/commands/massu-golden-path/references/competitive-mode.md +273 -0
  47. package/commands/massu-golden-path/references/error-handling.md +121 -0
  48. package/commands/massu-golden-path/references/phase-0-requirements.md +53 -0
  49. package/commands/massu-golden-path/references/phase-1-plan-creation.md +168 -0
  50. package/commands/massu-golden-path/references/phase-2-implementation.md +397 -0
  51. package/commands/massu-golden-path/references/phase-2.5-gap-analyzer.md +156 -0
  52. package/commands/massu-golden-path/references/phase-3-simplify.md +40 -0
  53. package/commands/massu-golden-path/references/phase-4-commit.md +94 -0
  54. package/commands/massu-golden-path/references/phase-5-push.md +116 -0
  55. package/commands/massu-golden-path/references/phase-5.5-production-verify.md +170 -0
  56. package/commands/massu-golden-path/references/phase-6-completion.md +113 -0
  57. package/commands/massu-golden-path/references/qa-evaluator-spec.md +137 -0
  58. package/commands/massu-golden-path/references/sprint-contract-protocol.md +117 -0
  59. package/commands/massu-golden-path/references/vr-visual-calibration.md +73 -0
  60. package/commands/massu-golden-path.md +114 -848
  61. package/commands/massu-guide.md +72 -69
  62. package/commands/massu-hooks.md +27 -12
  63. package/commands/massu-hotfix.md +221 -144
  64. package/commands/massu-incident.md +49 -20
  65. package/commands/massu-infra-audit.md +187 -0
  66. package/commands/massu-learning-audit.md +211 -0
  67. package/commands/massu-loop/references/auto-learning.md +49 -0
  68. package/commands/massu-loop/references/checkpoint-audit.md +40 -0
  69. package/commands/massu-loop/references/guardrails.md +17 -0
  70. package/commands/massu-loop/references/iteration-structure.md +115 -0
  71. package/commands/massu-loop/references/loop-controller.md +188 -0
  72. package/commands/massu-loop/references/plan-extraction.md +78 -0
  73. package/commands/massu-loop/references/vr-plan-spec.md +140 -0
  74. package/commands/massu-loop-playwright.md +9 -9
  75. package/commands/massu-loop.md +115 -670
  76. package/commands/massu-new-pattern.md +423 -0
  77. package/commands/massu-perf.md +422 -0
  78. package/commands/massu-plan-audit.md +1 -1
  79. package/commands/massu-plan.md +389 -122
  80. package/commands/massu-production-verify.md +433 -0
  81. package/commands/massu-push.md +62 -378
  82. package/commands/massu-recap.md +29 -3
  83. package/commands/massu-rollback.md +613 -0
  84. package/commands/massu-scaffold-hook.md +2 -4
  85. package/commands/massu-scaffold-page.md +2 -3
  86. package/commands/massu-scaffold-router.md +1 -2
  87. package/commands/massu-security.md +619 -0
  88. package/commands/massu-simplify.md +115 -85
  89. package/commands/massu-squirrels.md +2 -2
  90. package/commands/massu-tdd.md +38 -22
  91. package/commands/massu-test.md +3 -3
  92. package/commands/massu-type-mismatch-audit.md +469 -0
  93. package/commands/massu-ui-audit.md +587 -0
  94. package/commands/massu-verify-playwright.md +287 -32
  95. package/commands/massu-verify.md +150 -46
  96. package/dist/cli.js +146 -95
  97. package/package.json +6 -2
  98. package/patterns/build-patterns.md +302 -0
  99. package/patterns/component-patterns.md +246 -0
  100. package/patterns/display-patterns.md +185 -0
  101. package/patterns/form-patterns.md +890 -0
  102. package/patterns/integration-testing-checklist.md +445 -0
  103. package/patterns/security-patterns.md +219 -0
  104. package/patterns/testing-patterns.md +569 -0
  105. package/patterns/tool-routing.md +81 -0
  106. package/patterns/ui-patterns.md +371 -0
  107. package/protocols/plan-implementation.md +267 -0
  108. package/protocols/recovery.md +225 -0
  109. package/protocols/verification.md +404 -0
  110. package/reference/command-taxonomy.md +178 -0
  111. package/reference/cr-rules-reference.md +76 -0
  112. package/reference/hook-execution-order.md +148 -0
  113. package/reference/lessons-learned.md +175 -0
  114. package/reference/patterns-quickref.md +208 -0
  115. package/reference/standards.md +135 -0
  116. package/reference/subagents-reference.md +17 -0
  117. package/reference/vr-verification-reference.md +867 -0
  118. package/src/commands/install-commands.ts +149 -53
@@ -0,0 +1,569 @@
1
+ # Testing Patterns
2
+
3
+ **Purpose**: Testing pyramid, patterns, and best practices for unit, integration, and E2E tests.
4
+
5
+ **When to Read**: Before writing tests, setting up test infrastructure, or debugging test failures.
6
+
7
+ ---
8
+
9
+ ## Testing Pyramid
10
+
11
+ | Level | Coverage | Tools | Speed |
12
+ |-------|----------|-------|-------|
13
+ | Unit | 80% | Vitest + Testing Library | Fast (seconds) |
14
+ | Integration | 15% | Vitest + tRPC test utils | Medium (seconds) |
15
+ | E2E | 5% | Playwright | Slow (minutes) |
16
+
17
+ ---
18
+
19
+ ## 1. Unit Testing (80% of Tests)
20
+
21
+ ### Location Convention
22
+
23
+ ```
24
+ src/
25
+ ├── __tests__/ # Unit tests
26
+ │ ├── lib/ # Utility tests
27
+ │ │ └── calculateTotal.test.ts
28
+ │ ├── components/ # Component tests
29
+ │ │ └── StatusBadge.test.tsx
30
+ │ └── hooks/ # Hook tests
31
+ │ └── useDebounce.test.ts
32
+ ```
33
+
34
+ ### Example 1: Business Logic
35
+
36
+ ```typescript
37
+ // src/__tests__/lib/calculateTotal.test.ts
38
+ import { describe, it, expect } from 'vitest';
39
+ import { calculateOrderTotal } from '@/lib/calculations/order';
40
+
41
+ describe('calculateOrderTotal', () => {
42
+ it('should calculate total with tax', () => {
43
+ const items = [
44
+ { price: 100, quantity: 2 },
45
+ { price: 50, quantity: 1 },
46
+ ];
47
+
48
+ const result = calculateOrderTotal(items, { taxRate: 0.08 });
49
+
50
+ expect(result.subtotal).toBe(250);
51
+ expect(result.tax).toBe(20);
52
+ expect(result.total).toBe(270);
53
+ });
54
+
55
+ it('should handle empty items', () => {
56
+ const result = calculateOrderTotal([], { taxRate: 0.08 });
57
+
58
+ expect(result.subtotal).toBe(0);
59
+ expect(result.tax).toBe(0);
60
+ expect(result.total).toBe(0);
61
+ });
62
+
63
+ it('should apply discount', () => {
64
+ const items = [{ price: 100, quantity: 1 }];
65
+
66
+ const result = calculateOrderTotal(items, {
67
+ taxRate: 0.08,
68
+ discountPercent: 10,
69
+ });
70
+
71
+ expect(result.subtotal).toBe(100);
72
+ expect(result.discount).toBe(10);
73
+ expect(result.tax).toBe(7.2); // Tax on discounted amount
74
+ expect(result.total).toBe(97.2);
75
+ });
76
+ });
77
+ ```
78
+
79
+ ### Example 2: React Component
80
+
81
+ ```typescript
82
+ // src/__tests__/components/StatusBadge.test.tsx
83
+ import { describe, it, expect } from 'vitest';
84
+ import { render, screen } from '@testing-library/react';
85
+ import { StatusBadge } from '@/components/common/StatusBadge';
86
+
87
+ describe('StatusBadge', () => {
88
+ it('should render active status with green badge', () => {
89
+ render(<StatusBadge status="active" />);
90
+
91
+ const badge = screen.getByText('Active');
92
+ expect(badge).toBeInTheDocument();
93
+ expect(badge.className).toContain('badge-success');
94
+ });
95
+
96
+ it('should handle null status gracefully', () => {
97
+ render(<StatusBadge status={null} />);
98
+
99
+ const badge = screen.getByText('Pending');
100
+ expect(badge).toBeInTheDocument();
101
+ });
102
+
103
+ it('should capitalize status text', () => {
104
+ render(<StatusBadge status="in_progress" />);
105
+
106
+ expect(screen.getByText('In Progress')).toBeInTheDocument();
107
+ });
108
+ });
109
+ ```
110
+
111
+ ### Example 3: Custom Hook
112
+
113
+ ```typescript
114
+ // src/__tests__/hooks/useDebounce.test.ts
115
+ import { describe, it, expect, vi } from 'vitest';
116
+ import { renderHook, act } from '@testing-library/react';
117
+ import { useDebounce } from '@/hooks/useDebounce';
118
+
119
+ describe('useDebounce', () => {
120
+ it('should debounce value changes', async () => {
121
+ vi.useFakeTimers();
122
+
123
+ const { result, rerender } = renderHook(
124
+ ({ value }) => useDebounce(value, 300),
125
+ { initialProps: { value: 'initial' } }
126
+ );
127
+
128
+ expect(result.current).toBe('initial');
129
+
130
+ rerender({ value: 'updated' });
131
+ expect(result.current).toBe('initial'); // Not yet updated
132
+
133
+ act(() => {
134
+ vi.advanceTimersByTime(300);
135
+ });
136
+
137
+ expect(result.current).toBe('updated'); // Now updated
138
+
139
+ vi.useRealTimers();
140
+ });
141
+ });
142
+ ```
143
+
144
+ ---
145
+
146
+ ## 2. Integration Testing (15% of Tests)
147
+
148
+ ### Location Convention
149
+
150
+ ```
151
+ tests/
152
+ ├── integration/
153
+ │ ├── routers/ # tRPC router tests
154
+ │ │ └── orders.test.ts
155
+ │ ├── database/ # Database transaction tests
156
+ │ │ └── transactions.test.ts
157
+ │ └── helpers/
158
+ │ └── trpc.ts # Test caller setup
159
+ ```
160
+
161
+ ### tRPC Router Testing
162
+
163
+ ```typescript
164
+ // tests/integration/routers/orders.test.ts
165
+ import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
166
+ import { createCaller } from '../helpers/trpc';
167
+ import { PrismaClient } from '@prisma/client';
168
+
169
+ const prisma = new PrismaClient();
170
+
171
+ describe('Integration: Orders Router', () => {
172
+ let caller: ReturnType<typeof createCaller>;
173
+ const testCustomerId = 'test-customer-123';
174
+
175
+ beforeAll(async () => {
176
+ caller = createCaller({ userId: 'test-user-id' });
177
+
178
+ // Setup test data
179
+ await prisma.customer.create({
180
+ data: { id: testCustomerId, name: 'Test Customer', email: 'test@example.com' }
181
+ });
182
+
183
+ await prisma.product.create({
184
+ data: { id: 'test-product-789', name: 'Test Product', price: 100, inventory_quantity: 100 }
185
+ });
186
+ });
187
+
188
+ afterAll(async () => {
189
+ await prisma.orderItem.deleteMany({ where: { order: { customerId: testCustomerId } } });
190
+ await prisma.order.deleteMany({ where: { customerId: testCustomerId } });
191
+ await prisma.product.deleteMany({ where: { id: 'test-product-789' } });
192
+ await prisma.customer.deleteMany({ where: { id: testCustomerId } });
193
+ await prisma.$disconnect();
194
+ });
195
+
196
+ it('should create order and update inventory', async () => {
197
+ const result = await caller.orders.create({
198
+ customerId: testCustomerId,
199
+ items: [
200
+ { productId: 'test-product-789', quantity: 5, price: 100 }
201
+ ]
202
+ });
203
+
204
+ expect(result.total).toBe(500);
205
+ expect(result.status).toBe('pending');
206
+
207
+ // Verify inventory updated
208
+ const product = await prisma.product.findUnique({
209
+ where: { id: 'test-product-789' }
210
+ });
211
+ expect(product?.inventory_quantity).toBe(95);
212
+ });
213
+
214
+ it('should fail when insufficient inventory', async () => {
215
+ await expect(
216
+ caller.orders.create({
217
+ customerId: testCustomerId,
218
+ items: [
219
+ { productId: 'test-product-789', quantity: 200, price: 100 }
220
+ ]
221
+ })
222
+ ).rejects.toThrow('Insufficient inventory');
223
+ });
224
+ });
225
+ ```
226
+
227
+ ### Integration Test Best Practices
228
+
229
+ **1. Use Test Database**
230
+ ```typescript
231
+ // .env.test
232
+ DATABASE_URL="postgresql://user:pass@localhost:5432/test_db"
233
+ ```
234
+
235
+ **2. Clean Test Data After Each Test**
236
+ ```typescript
237
+ afterEach(async () => {
238
+ // Delete in reverse foreign key order
239
+ await prisma.orderItem.deleteMany({ where: { orderId: testOrderId } });
240
+ await prisma.order.deleteMany({ where: { id: testOrderId } });
241
+ });
242
+ ```
243
+
244
+ **3. Test Error Cases**
245
+ ```typescript
246
+ it('should handle database constraint violations', async () => {
247
+ await expect(
248
+ prisma.order.create({ data: { customerId: 'non-existent' } })
249
+ ).rejects.toThrow('Foreign key constraint');
250
+ });
251
+ ```
252
+
253
+ **4. Use Factory Functions for Test Data**
254
+ ```typescript
255
+ // tests/factories/order-factory.ts
256
+ export async function createTestOrder(overrides = {}) {
257
+ return await prisma.order.create({
258
+ data: {
259
+ userId: 'test-user',
260
+ customerId: 'test-customer',
261
+ total: 100,
262
+ status: 'pending',
263
+ ...overrides
264
+ }
265
+ });
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## 2.1 Router Contract Validation (Integration Test Prerequisite)
272
+
273
+ ### CRITICAL: Verify Router Methods Exist BEFORE Writing Tests
274
+
275
+ **Why This Matters**: Tests written without verifying router methods exist cause "No procedure found on path" errors. This wastes significant debugging time.
276
+
277
+ ### The 4-Step Verification Process
278
+
279
+ Before writing ANY integration test:
280
+
281
+ ```typescript
282
+ /**
283
+ * STEP 1: Read Actual Router File
284
+ * ================================
285
+ */
286
+ // Terminal command:
287
+ cat src/server/api/routers/my-router.ts | grep -A2 "export const"
288
+
289
+ /**
290
+ * STEP 2: Document Available Methods in Test Header
291
+ * ==================================================
292
+ */
293
+
294
+ /**
295
+ * Integration Tests: My Router
296
+ *
297
+ * ROUTER METHODS VERIFIED (date)
298
+ * Source: src/server/api/routers/my-router.ts
299
+ *
300
+ * Available Methods:
301
+ * - method1(params) - Description
302
+ * - method2(params) - Description
303
+ *
304
+ * Methods NOT Available:
305
+ * - create() - Does NOT exist (use other router instead)
306
+ */
307
+
308
+ /**
309
+ * STEP 3: Run Automated Validation
310
+ * =================================
311
+ */
312
+ npm run validate:router-contracts
313
+
314
+ /**
315
+ * STEP 4: Commit Tests Immediately
316
+ * =================================
317
+ */
318
+ git add tests/integration/
319
+ git commit -m "test(integration): add router lifecycle tests"
320
+ ```
321
+
322
+ ### Common API Mismatches
323
+
324
+ ```typescript
325
+ // WRONG - Assumed method name
326
+ const result = await caller.myRouter.create({ name: 'Test' });
327
+ // Error: No procedure found on path 'myRouter,create'
328
+
329
+ // CORRECT - Verified method name
330
+ const result = await caller.myRouter.executeAction({
331
+ actionId: existingId,
332
+ context: { trigger: 'manual' }
333
+ });
334
+ ```
335
+
336
+ ---
337
+
338
+ ## 3. E2E Testing (5% of Tests)
339
+
340
+ ### Critical Test Paths
341
+
342
+ | # | Test | Coverage |
343
+ |---|------|----------|
344
+ | 1 | Authentication | Login, logout, session persistence |
345
+ | 2 | Admin Access | Admin portal access control |
346
+ | 3 | Order Creation | End-to-end order flow |
347
+ | 4 | Payment Processing | Payment integration |
348
+ | 5 | Document Upload | File upload/download |
349
+ | 6 | Search | Global search functionality |
350
+
351
+ ### When to Add E2E Tests
352
+
353
+ **DO add for:**
354
+ - Critical revenue-generating flows (checkout, payment)
355
+ - Security-critical paths (authentication, authorization)
356
+ - Cross-system integrations (payment gateways, APIs)
357
+ - Compliance-required workflows (audit trails)
358
+
359
+ **DO NOT add for:**
360
+ - Features covered by unit/integration tests
361
+ - UI styling or layout changes
362
+ - Admin-only features (unless security-critical)
363
+
364
+ ### E2E Best Practices
365
+
366
+ **1. Keep Tests Independent**
367
+ ```typescript
368
+ // WRONG - Tests depend on each other
369
+ test('create order', async ({ page }) => { /* ... */ });
370
+ test('view order', async ({ page }) => {
371
+ // Uses order from previous test (BRITTLE!)
372
+ });
373
+
374
+ // CORRECT - Self-contained
375
+ test('view order', async ({ page }) => {
376
+ const orderId = await createTestOrder();
377
+ await page.goto(`/orders/${orderId}`);
378
+ });
379
+ ```
380
+
381
+ **2. Use Page Object Pattern**
382
+ ```typescript
383
+ export class LoginPage {
384
+ constructor(private page: Page) {}
385
+
386
+ async goto() {
387
+ await this.page.goto('/auth/login');
388
+ }
389
+
390
+ async login(email: string, password: string) {
391
+ await this.page.fill('[name="email"]', email);
392
+ await this.page.fill('[name="password"]', password);
393
+ await this.page.click('button[type="submit"]');
394
+ }
395
+ }
396
+ ```
397
+
398
+ **3. Wait for Network**
399
+ ```typescript
400
+ // WRONG
401
+ await page.click('button');
402
+ await expect(page.locator('.result')).toBeVisible();
403
+
404
+ // CORRECT
405
+ await page.click('button');
406
+ await page.waitForLoadState('networkidle');
407
+ await expect(page.locator('.result')).toBeVisible();
408
+ ```
409
+
410
+ ---
411
+
412
+ ## 4. Test Data Management
413
+
414
+ ### Mock Data Strategies
415
+
416
+ | Strategy | Use Case | Example |
417
+ |----------|----------|---------|
418
+ | Inline mocks | Unit tests | `{ name: 'John', email: 'john@example.com' }` |
419
+ | Factory functions | Integration tests | `createTestUser({ email: 'specific@test.com' })` |
420
+ | Database seeding | E2E tests | `seedTestData()` in beforeAll |
421
+
422
+ ### Test Isolation
423
+
424
+ ```typescript
425
+ // Use unique test IDs
426
+ const testId = `test-${Date.now()}-${Math.random().toString(36).slice(2)}`;
427
+
428
+ // Clean up after each test
429
+ afterEach(async () => {
430
+ await prisma.order.deleteMany({ where: { userId: testId } });
431
+ });
432
+
433
+ // WRONG - Shared state
434
+ let sharedOrder: Order;
435
+ beforeEach(() => { sharedOrder = createOrder(); });
436
+
437
+ // CORRECT - Each test creates its own
438
+ it('should update order', () => {
439
+ const order = createOrder();
440
+ // Test with this order
441
+ });
442
+ ```
443
+
444
+ ---
445
+
446
+ ## 5. Development Workflow
447
+
448
+ ### Pre-Commit Checks
449
+
450
+ ```json
451
+ {
452
+ "lint-staged": {
453
+ "*.{ts,tsx}": [
454
+ "npm run test -- --related --run",
455
+ "npm run type-check",
456
+ "npm run lint --fix"
457
+ ]
458
+ }
459
+ }
460
+ ```
461
+
462
+ ### Local Development
463
+
464
+ ```bash
465
+ # Before starting work
466
+ git pull origin main && npm install && npm run test
467
+
468
+ # During development
469
+ npm run test -- --watch
470
+
471
+ # Before committing
472
+ npm run test && npm run type-check && npm run lint
473
+
474
+ # Before pushing
475
+ npm run build
476
+ ```
477
+
478
+ ---
479
+
480
+ ## 6. Common Testing Patterns
481
+
482
+ ### Testing Async Functions
483
+ ```typescript
484
+ it('should fetch data', async () => {
485
+ const result = await fetchUser('user-123');
486
+ expect(result.email).toBe('test@example.com');
487
+ });
488
+ ```
489
+
490
+ ### Testing Error Handling
491
+ ```typescript
492
+ it('should throw for invalid input', async () => {
493
+ await expect(createOrder({ items: [] }))
494
+ .rejects.toThrow('Order must have at least one item');
495
+ });
496
+ ```
497
+
498
+ ### Testing with Mocks
499
+ ```typescript
500
+ import { vi } from 'vitest';
501
+
502
+ it('should call external API', async () => {
503
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, json: async () => ({}) });
504
+ global.fetch = mockFetch;
505
+
506
+ await sendEmail('test@example.com', 'Hello');
507
+
508
+ expect(mockFetch).toHaveBeenCalledWith(
509
+ expect.stringContaining('/api/email'),
510
+ expect.objectContaining({ method: 'POST' })
511
+ );
512
+ });
513
+ ```
514
+
515
+ ### Testing React Components
516
+ ```typescript
517
+ import { render, screen } from '@testing-library/react';
518
+ import userEvent from '@testing-library/user-event';
519
+
520
+ it('should submit form', async () => {
521
+ const handleSubmit = vi.fn();
522
+ render(<LoginForm onSubmit={handleSubmit} />);
523
+
524
+ await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
525
+ await userEvent.type(screen.getByLabelText('Password'), 'password123');
526
+ await userEvent.click(screen.getByRole('button', { name: /submit/i }));
527
+
528
+ expect(handleSubmit).toHaveBeenCalledWith({
529
+ email: 'test@example.com',
530
+ password: 'password123'
531
+ });
532
+ });
533
+ ```
534
+
535
+ ---
536
+
537
+ ## 7. Troubleshooting
538
+
539
+ | Issue | Solution |
540
+ |-------|---------|
541
+ | Tests timing out | Increase timeout: `{ timeout: 10000 }` or globally in `vitest.config.ts` |
542
+ | Database tests failing | Clean database: `await prisma.$executeRaw\`TRUNCATE TABLE orders CASCADE\`` |
543
+ | Flaky E2E tests | Use `toPass` with retry: `await expect(async () => { ... }).toPass({ timeout: 5000 })` |
544
+
545
+ ---
546
+
547
+ ## Quick Reference
548
+
549
+ | Scenario | Test Type | Location |
550
+ |----------|-----------|----------|
551
+ | Business logic function | Unit | `src/__tests__/` |
552
+ | React component behavior | Unit | `src/__tests__/components/` |
553
+ | tRPC endpoint | Integration | `tests/integration/routers/` |
554
+ | Database transaction | Integration | `tests/integration/database/` |
555
+ | Login flow | E2E | `tests/e2e/critical/` |
556
+ | Payment processing | E2E | `tests/e2e/critical/` |
557
+
558
+ ```bash
559
+ npm run test # All unit + integration tests
560
+ npm run test -- --watch # Watch mode
561
+ npm run test:e2e # E2E tests
562
+ npm run type-check # TypeScript validation
563
+ npm run build # Verify production build
564
+ ```
565
+
566
+ ---
567
+
568
+ **Document Status**: ACTIVE
569
+ **Compliance**: Mandatory testing pyramid enforcement
@@ -0,0 +1,81 @@
1
+ # Tool Routing Patterns
2
+
3
+ **Purpose**: Decision trees for selecting the correct tool/MCP for browser automation, Google services, and code search.
4
+
5
+ **When to Read**: Before using any browser automation, Google service, or code search tool.
6
+
7
+ ---
8
+
9
+ ## Browser Automation Routing
10
+
11
+ | Need | Tool | Why |
12
+ |------|------|-----|
13
+ | Navigate + screenshot + verify | Playwright CLI (`browser_navigate`, `browser_snapshot`) | Deterministic, accessibility tree, no vision needed |
14
+ | Fill forms + click buttons | Playwright CLI (`browser_click`, `browser_fill_form`) | Direct element interaction via ref IDs |
15
+ | Complex multi-step flows | Playwright CLI (multiple calls) | Sequential, reliable |
16
+ | Visual design review | Playwright CLI `browser_take_screenshot` + vision analysis | Screenshot for LLM visual evaluation |
17
+ | Natural language interaction | Stagehand MCP | When element selectors are unclear |
18
+ | Generic web scraping | Browser MCP | Non-app browsing tasks |
19
+
20
+ ### Decision Tree
21
+
22
+ ```
23
+ Need browser automation?
24
+ ├── Testing YOUR app (localhost/preview)?
25
+ │ ├── Know the element? → Playwright CLI (browser_click, browser_fill_form)
26
+ │ ├── Need page state? → Playwright CLI (browser_snapshot)
27
+ │ ├── Need screenshot? → Playwright CLI (browser_take_screenshot)
28
+ │ └── Complex flow? → Playwright CLI (sequential calls)
29
+ ├── Scraping external site?
30
+ │ └── → Browser MCP or WebFetch
31
+ └── Natural language interaction needed?
32
+ └── → Stagehand MCP
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Google Services Routing
38
+
39
+ | Need | Tool | Why |
40
+ |------|------|-----|
41
+ | Read/write spreadsheets | Google Workspace MCP | Direct API access |
42
+ | Send email | Google Workspace MCP (`send_gmail_message`) | Gmail API |
43
+ | Calendar events | Google Workspace MCP (`get_events`, `manage_event`) | Calendar API |
44
+ | Drive files | Google Workspace MCP (`search_drive_files`, `get_drive_file_content`) | Drive API |
45
+ | Apps Script management | Google Workspace MCP (`get_script_content`, `update_script_content`) | Direct script access |
46
+ | Run Apps Script function | Google Workspace MCP (`run_script_function`) | Execute deployed functions |
47
+ | Create Apps Script project | Google Workspace MCP (`create_script_project`) | Project scaffolding |
48
+
49
+ ---
50
+
51
+ ## Code Search Routing
52
+
53
+ | Need | Tool | Why |
54
+ |------|------|-----|
55
+ | Find files by name/pattern | Glob | Fast pattern matching, sorted by modification time |
56
+ | Search file contents | Grep | Regex search with context, line numbers |
57
+ | Understand call graph | Codegraph MCP (`codegraph_callers`, `codegraph_callees`) | Relationship analysis |
58
+ | Impact analysis | Codegraph MCP (`codegraph_impact`) | What would break if X changes |
59
+ | Multi-round exploration | Task agent | Open-ended investigation |
60
+
61
+ ### Decision Tree
62
+
63
+ ```
64
+ Need to find something in code?
65
+ ├── Know the filename pattern?
66
+ │ └── → Glob ("**/*.tsx", "src/**/*service*")
67
+ ├── Know what the code contains?
68
+ │ ├── Simple pattern? → Grep (pattern, path)
69
+ │ └── Complex regex? → Grep (multiline: true)
70
+ ├── Need to understand relationships?
71
+ │ ├── Who calls this? → codegraph_callers
72
+ │ ├── What does this call? → codegraph_callees
73
+ │ └── What breaks if I change this? → codegraph_impact
74
+ └── Open-ended exploration?
75
+ └── → Task agent (multiple search rounds)
76
+ ```
77
+
78
+ ---
79
+
80
+ **Document Status**: ACTIVE
81
+ **Compliance**: Use routing tables before selecting tools