opencode-metis 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 (156) hide show
  1. package/README.md +140 -0
  2. package/dist/cli.cjs +63 -0
  3. package/dist/mcp-server.cjs +51 -0
  4. package/dist/plugin.cjs +4 -0
  5. package/dist/worker.cjs +224 -0
  6. package/opencode/agent/the-analyst/feature-prioritization.md +66 -0
  7. package/opencode/agent/the-analyst/market-research.md +77 -0
  8. package/opencode/agent/the-analyst/project-coordination.md +81 -0
  9. package/opencode/agent/the-analyst/requirements-analysis.md +77 -0
  10. package/opencode/agent/the-architect/compatibility-review.md +138 -0
  11. package/opencode/agent/the-architect/complexity-review.md +137 -0
  12. package/opencode/agent/the-architect/quality-review.md +67 -0
  13. package/opencode/agent/the-architect/security-review.md +127 -0
  14. package/opencode/agent/the-architect/system-architecture.md +119 -0
  15. package/opencode/agent/the-architect/system-documentation.md +83 -0
  16. package/opencode/agent/the-architect/technology-research.md +85 -0
  17. package/opencode/agent/the-chief.md +79 -0
  18. package/opencode/agent/the-designer/accessibility-implementation.md +101 -0
  19. package/opencode/agent/the-designer/design-foundation.md +74 -0
  20. package/opencode/agent/the-designer/interaction-architecture.md +75 -0
  21. package/opencode/agent/the-designer/user-research.md +70 -0
  22. package/opencode/agent/the-meta-agent.md +155 -0
  23. package/opencode/agent/the-platform-engineer/ci-cd-pipelines.md +109 -0
  24. package/opencode/agent/the-platform-engineer/containerization.md +106 -0
  25. package/opencode/agent/the-platform-engineer/data-architecture.md +81 -0
  26. package/opencode/agent/the-platform-engineer/dependency-review.md +144 -0
  27. package/opencode/agent/the-platform-engineer/deployment-automation.md +81 -0
  28. package/opencode/agent/the-platform-engineer/infrastructure-as-code.md +107 -0
  29. package/opencode/agent/the-platform-engineer/performance-tuning.md +82 -0
  30. package/opencode/agent/the-platform-engineer/pipeline-engineering.md +81 -0
  31. package/opencode/agent/the-platform-engineer/production-monitoring.md +105 -0
  32. package/opencode/agent/the-qa-engineer/exploratory-testing.md +66 -0
  33. package/opencode/agent/the-qa-engineer/performance-testing.md +81 -0
  34. package/opencode/agent/the-qa-engineer/quality-assurance.md +77 -0
  35. package/opencode/agent/the-qa-engineer/test-execution.md +66 -0
  36. package/opencode/agent/the-software-engineer/api-development.md +78 -0
  37. package/opencode/agent/the-software-engineer/component-development.md +79 -0
  38. package/opencode/agent/the-software-engineer/concurrency-review.md +141 -0
  39. package/opencode/agent/the-software-engineer/domain-modeling.md +66 -0
  40. package/opencode/agent/the-software-engineer/performance-optimization.md +113 -0
  41. package/opencode/command/analyze.md +149 -0
  42. package/opencode/command/constitution.md +178 -0
  43. package/opencode/command/debug.md +194 -0
  44. package/opencode/command/document.md +178 -0
  45. package/opencode/command/implement.md +225 -0
  46. package/opencode/command/refactor.md +207 -0
  47. package/opencode/command/review.md +229 -0
  48. package/opencode/command/simplify.md +267 -0
  49. package/opencode/command/specify.md +191 -0
  50. package/opencode/command/validate.md +224 -0
  51. package/opencode/skill/accessibility-design/SKILL.md +566 -0
  52. package/opencode/skill/accessibility-design/checklists/wcag-checklist.md +435 -0
  53. package/opencode/skill/agent-coordination/SKILL.md +224 -0
  54. package/opencode/skill/api-contract-design/SKILL.md +550 -0
  55. package/opencode/skill/api-contract-design/templates/graphql-schema-template.md +818 -0
  56. package/opencode/skill/api-contract-design/templates/rest-api-template.md +417 -0
  57. package/opencode/skill/architecture-design/SKILL.md +160 -0
  58. package/opencode/skill/architecture-design/examples/architecture-examples.md +170 -0
  59. package/opencode/skill/architecture-design/template.md +749 -0
  60. package/opencode/skill/architecture-design/validation.md +99 -0
  61. package/opencode/skill/architecture-selection/SKILL.md +522 -0
  62. package/opencode/skill/architecture-selection/examples/adrs/001-example-adr.md +71 -0
  63. package/opencode/skill/architecture-selection/examples/architecture-patterns.md +239 -0
  64. package/opencode/skill/bug-diagnosis/SKILL.md +235 -0
  65. package/opencode/skill/code-quality-review/SKILL.md +337 -0
  66. package/opencode/skill/code-quality-review/examples/anti-patterns.md +629 -0
  67. package/opencode/skill/code-quality-review/reference.md +322 -0
  68. package/opencode/skill/code-review/SKILL.md +363 -0
  69. package/opencode/skill/code-review/reference.md +450 -0
  70. package/opencode/skill/codebase-analysis/SKILL.md +139 -0
  71. package/opencode/skill/codebase-navigation/SKILL.md +227 -0
  72. package/opencode/skill/codebase-navigation/examples/exploration-patterns.md +263 -0
  73. package/opencode/skill/coding-conventions/SKILL.md +178 -0
  74. package/opencode/skill/coding-conventions/checklists/accessibility-checklist.md +176 -0
  75. package/opencode/skill/coding-conventions/checklists/performance-checklist.md +154 -0
  76. package/opencode/skill/coding-conventions/checklists/security-checklist.md +127 -0
  77. package/opencode/skill/constitution-validation/SKILL.md +315 -0
  78. package/opencode/skill/constitution-validation/examples/CONSTITUTION.md +202 -0
  79. package/opencode/skill/constitution-validation/reference/rule-patterns.md +328 -0
  80. package/opencode/skill/constitution-validation/template.md +115 -0
  81. package/opencode/skill/context-preservation/SKILL.md +445 -0
  82. package/opencode/skill/data-modeling/SKILL.md +385 -0
  83. package/opencode/skill/data-modeling/templates/schema-design-template.md +268 -0
  84. package/opencode/skill/deployment-pipeline-design/SKILL.md +579 -0
  85. package/opencode/skill/deployment-pipeline-design/templates/pipeline-template.md +633 -0
  86. package/opencode/skill/documentation-extraction/SKILL.md +259 -0
  87. package/opencode/skill/documentation-sync/SKILL.md +431 -0
  88. package/opencode/skill/domain-driven-design/SKILL.md +509 -0
  89. package/opencode/skill/domain-driven-design/examples/ddd-patterns.md +688 -0
  90. package/opencode/skill/domain-driven-design/reference.md +465 -0
  91. package/opencode/skill/drift-detection/SKILL.md +383 -0
  92. package/opencode/skill/drift-detection/reference.md +340 -0
  93. package/opencode/skill/error-recovery/SKILL.md +162 -0
  94. package/opencode/skill/error-recovery/examples/error-patterns.md +484 -0
  95. package/opencode/skill/feature-prioritization/SKILL.md +419 -0
  96. package/opencode/skill/feature-prioritization/examples/rice-template.md +139 -0
  97. package/opencode/skill/feature-prioritization/reference.md +256 -0
  98. package/opencode/skill/git-workflow/SKILL.md +453 -0
  99. package/opencode/skill/implementation-planning/SKILL.md +215 -0
  100. package/opencode/skill/implementation-planning/examples/phase-examples.md +217 -0
  101. package/opencode/skill/implementation-planning/template.md +220 -0
  102. package/opencode/skill/implementation-planning/validation.md +88 -0
  103. package/opencode/skill/implementation-verification/SKILL.md +272 -0
  104. package/opencode/skill/knowledge-capture/SKILL.md +265 -0
  105. package/opencode/skill/knowledge-capture/reference/knowledge-capture.md +402 -0
  106. package/opencode/skill/knowledge-capture/reference.md +444 -0
  107. package/opencode/skill/knowledge-capture/templates/domain-template.md +325 -0
  108. package/opencode/skill/knowledge-capture/templates/interface-template.md +255 -0
  109. package/opencode/skill/knowledge-capture/templates/pattern-template.md +144 -0
  110. package/opencode/skill/observability-design/SKILL.md +291 -0
  111. package/opencode/skill/observability-design/references/monitoring-patterns.md +461 -0
  112. package/opencode/skill/pattern-detection/SKILL.md +171 -0
  113. package/opencode/skill/pattern-detection/examples/common-patterns.md +359 -0
  114. package/opencode/skill/performance-analysis/SKILL.md +266 -0
  115. package/opencode/skill/performance-analysis/references/profiling-tools.md +499 -0
  116. package/opencode/skill/requirements-analysis/SKILL.md +139 -0
  117. package/opencode/skill/requirements-analysis/examples/good-prd.md +66 -0
  118. package/opencode/skill/requirements-analysis/template.md +177 -0
  119. package/opencode/skill/requirements-analysis/validation.md +69 -0
  120. package/opencode/skill/requirements-elicitation/SKILL.md +518 -0
  121. package/opencode/skill/requirements-elicitation/examples/interview-questions.md +226 -0
  122. package/opencode/skill/requirements-elicitation/examples/user-stories.md +414 -0
  123. package/opencode/skill/safe-refactoring/SKILL.md +312 -0
  124. package/opencode/skill/safe-refactoring/reference/code-smells.md +347 -0
  125. package/opencode/skill/security-assessment/SKILL.md +421 -0
  126. package/opencode/skill/security-assessment/checklists/security-review-checklist.md +285 -0
  127. package/opencode/skill/specification-management/SKILL.md +143 -0
  128. package/opencode/skill/specification-management/readme-template.md +32 -0
  129. package/opencode/skill/specification-management/reference.md +115 -0
  130. package/opencode/skill/specification-management/spec.py +229 -0
  131. package/opencode/skill/specification-validation/SKILL.md +397 -0
  132. package/opencode/skill/specification-validation/reference/3cs-framework.md +306 -0
  133. package/opencode/skill/specification-validation/reference/ambiguity-detection.md +132 -0
  134. package/opencode/skill/specification-validation/reference/constitution-validation.md +301 -0
  135. package/opencode/skill/specification-validation/reference/drift-detection.md +383 -0
  136. package/opencode/skill/task-delegation/SKILL.md +607 -0
  137. package/opencode/skill/task-delegation/examples/file-coordination.md +495 -0
  138. package/opencode/skill/task-delegation/examples/parallel-research.md +337 -0
  139. package/opencode/skill/task-delegation/examples/sequential-build.md +504 -0
  140. package/opencode/skill/task-delegation/reference.md +825 -0
  141. package/opencode/skill/tech-stack-detection/SKILL.md +89 -0
  142. package/opencode/skill/tech-stack-detection/references/framework-signatures.md +598 -0
  143. package/opencode/skill/technical-writing/SKILL.md +190 -0
  144. package/opencode/skill/technical-writing/templates/adr-template.md +205 -0
  145. package/opencode/skill/technical-writing/templates/system-doc-template.md +380 -0
  146. package/opencode/skill/test-design/SKILL.md +464 -0
  147. package/opencode/skill/test-design/examples/test-pyramid.md +724 -0
  148. package/opencode/skill/testing/SKILL.md +213 -0
  149. package/opencode/skill/testing/examples/test-pyramid.md +724 -0
  150. package/opencode/skill/user-insight-synthesis/SKILL.md +576 -0
  151. package/opencode/skill/user-insight-synthesis/templates/research-plan-template.md +217 -0
  152. package/opencode/skill/user-research/SKILL.md +508 -0
  153. package/opencode/skill/user-research/examples/interview-questions.md +265 -0
  154. package/opencode/skill/user-research/examples/personas.md +267 -0
  155. package/opencode/skill/vibe-security/SKILL.md +654 -0
  156. package/package.json +45 -0
@@ -0,0 +1,464 @@
1
+ ---
2
+ name: test-design
3
+ description: Apply test pyramid principles, coverage targets, and framework-specific patterns. Use when designing test suites, reviewing test coverage, or implementing tests. Covers Jest, Pytest, and common testing frameworks with naming conventions and organization patterns.
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ category: development
8
+ version: "1.0"
9
+ ---
10
+
11
+ # Testing Strategies
12
+
13
+ Roleplay as a development specialist that provides comprehensive testing methodology including test pyramid structure, coverage targets, framework-specific patterns, and test organization conventions.
14
+
15
+ TestDesign {
16
+ Activation {
17
+ When designing test suites for new features or projects
18
+ When reviewing test coverage and identifying gaps
19
+ When implementing unit, integration, or E2E tests
20
+ When establishing test naming and organization conventions
21
+ When selecting appropriate testing frameworks
22
+ When planning test automation strategies
23
+ }
24
+
25
+ Constraints {
26
+ Test behavior, not implementation
27
+ One assertion per behavior (multiple related assertions acceptable)
28
+ Tests must be independent and not share mutable state
29
+ Run tests before committing; never commit failing tests
30
+ Keep unit tests under 100ms execution time
31
+ Delete flaky tests or fix them immediately
32
+ }
33
+
34
+ TestPyramid {
35
+ ```
36
+ /\
37
+ / \ E2E Tests (5-10%)
38
+ /----\ - Critical user journeys
39
+ / \ - Slow, expensive, flaky-prone
40
+ /--------\
41
+ / \ Integration Tests (20-30%)
42
+ / Service \ - API contracts, database
43
+ /--------------\ - Component interactions
44
+ / \
45
+ / Unit Tests \ Unit Tests (60-70%)
46
+ /==================\ - Fast, isolated, deterministic
47
+ - Business logic focus
48
+ ```
49
+
50
+ DistributionGuidelines {
51
+ | Test Type | Target % | Execution Time | Scope |
52
+ |-------------|----------|----------------|--------------------------|
53
+ | Unit | 60-70% | < 100ms each | Single function/class |
54
+ | Integration | 20-30% | < 5s each | Service boundaries |
55
+ | E2E | 5-10% | < 30s each | Critical user paths |
56
+ }
57
+ }
58
+
59
+ CorePatterns {
60
+ TestBehaviorNotImplementation {
61
+ Tests should verify observable behavior, not internal implementation details
62
+
63
+ ```typescript
64
+ // CORRECT: Tests behavior
65
+ describe('ShoppingCart', () => {
66
+ it('calculates total with quantity discounts', () => {
67
+ const cart = new ShoppingCart();
68
+ cart.add({ sku: 'WIDGET', price: 10, quantity: 5 });
69
+
70
+ expect(cart.total).toBe(45); // 10% discount for 5+ items
71
+ });
72
+ });
73
+
74
+ // INCORRECT: Tests implementation
75
+ describe('ShoppingCart', () => {
76
+ it('calls _applyDiscount method', () => {
77
+ const cart = new ShoppingCart();
78
+ const spy = jest.spyOn(cart, '_applyDiscount');
79
+
80
+ cart.add({ sku: 'WIDGET', price: 10, quantity: 5 });
81
+
82
+ expect(spy).toHaveBeenCalledWith(0.1);
83
+ });
84
+ });
85
+ ```
86
+ }
87
+
88
+ ArrangeActAssertStructure {
89
+ Every test follows the AAA pattern for clarity and consistency
90
+
91
+ ```python
92
+ def test_user_registration_sends_welcome_email():
93
+ # Arrange
94
+ email_service = MockEmailService()
95
+ user_service = UserService(email_service=email_service)
96
+ registration_data = {"email": "new@user.com", "name": "New User"}
97
+
98
+ # Act
99
+ user_service.register(registration_data)
100
+
101
+ # Assert
102
+ assert email_service.sent_emails == [
103
+ {"to": "new@user.com", "template": "welcome"}
104
+ ]
105
+ ```
106
+ }
107
+
108
+ OneAssertionPerBehavior {
109
+ Each test verifies one specific behavior
110
+ Multiple assertions acceptable when verifying a single logical outcome
111
+
112
+ ```typescript
113
+ // CORRECT: One behavior, multiple related assertions
114
+ it('creates order with correct initial state', () => {
115
+ const order = createOrder(items);
116
+
117
+ expect(order.status).toBe('pending');
118
+ expect(order.items).toHaveLength(items.length);
119
+ expect(order.createdAt).toBeInstanceOf(Date);
120
+ });
121
+
122
+ // INCORRECT: Multiple unrelated behaviors
123
+ it('creates and processes order', () => {
124
+ const order = createOrder(items);
125
+ expect(order.status).toBe('pending');
126
+
127
+ processPayment(order);
128
+ expect(order.status).toBe('paid'); // Different behavior
129
+ });
130
+ ```
131
+ }
132
+
133
+ DescriptiveTestNames {
134
+ Test names describe the scenario and expected outcome
135
+
136
+ ```typescript
137
+ // Format: [unit]_[scenario]_[expected outcome]
138
+ // or: [action]_[condition]_[result]
139
+
140
+ // CORRECT
141
+ it('calculateTotal returns zero for empty cart')
142
+ it('validateEmail rejects addresses without @ symbol')
143
+ it('UserService throws NotFoundError when user does not exist')
144
+
145
+ // INCORRECT
146
+ it('test calculateTotal')
147
+ it('validateEmail works')
148
+ it('error handling')
149
+ ```
150
+ }
151
+
152
+ TestIsolation {
153
+ Tests must be independent and not share mutable state
154
+
155
+ ```python
156
+ # CORRECT: Fresh fixture per test
157
+ class TestOrderService:
158
+ def setup_method(self):
159
+ self.db = InMemoryDatabase()
160
+ self.service = OrderService(self.db)
161
+
162
+ def test_create_order(self):
163
+ order = self.service.create(items=[...])
164
+ assert order.id is not None
165
+
166
+ def test_list_orders_empty(self):
167
+ orders = self.service.list()
168
+ assert orders == []
169
+
170
+ # INCORRECT: Shared state between tests
171
+ db = Database() # Shared!
172
+
173
+ def test_create_order():
174
+ order = OrderService(db).create(items=[...])
175
+
176
+ def test_list_orders_empty():
177
+ orders = OrderService(db).list() # May see order from previous test!
178
+ ```
179
+ }
180
+ }
181
+
182
+ CoverageTargets {
183
+ RecommendedCoverageByCodeType {
184
+ | Code Type | Statement | Branch | Target |
185
+ |--------------------|-----------|--------|--------|
186
+ | Business Logic | 90% | 85% | High |
187
+ | API Controllers | 80% | 75% | Medium |
188
+ | Utility Functions | 95% | 90% | High |
189
+ | UI Components | 70% | 65% | Medium |
190
+ | Generated Code | N/A | N/A | Skip |
191
+ }
192
+
193
+ CoverageQualityOverQuantity {
194
+ Coverage percentage alone is insufficient. Prioritize:
195
+
196
+ 1. Critical paths: Authentication, payments, data integrity
197
+ 2. Edge cases: Boundaries, empty states, error conditions
198
+ 3. Regression prevention: Previously broken functionality
199
+ 4. Complex logic: High cyclomatic complexity areas
200
+ }
201
+ }
202
+
203
+ FrameworkSpecificPatterns {
204
+ Jest {
205
+ ```typescript
206
+ // File structure
207
+ src/
208
+ services/
209
+ UserService.ts
210
+ UserService.test.ts // Co-located
211
+
212
+ // Test setup
213
+ describe('UserService', () => {
214
+ let userService: UserService;
215
+ let mockRepo: jest.Mocked<UserRepository>;
216
+
217
+ beforeEach(() => {
218
+ mockRepo = {
219
+ findById: jest.fn(),
220
+ save: jest.fn(),
221
+ };
222
+ userService = new UserService(mockRepo);
223
+ });
224
+
225
+ afterEach(() => {
226
+ jest.clearAllMocks();
227
+ });
228
+
229
+ describe('getUser', () => {
230
+ it('returns user when found', async () => {
231
+ const expected = { id: '1', name: 'Alice' };
232
+ mockRepo.findById.mockResolvedValue(expected);
233
+
234
+ const result = await userService.getUser('1');
235
+
236
+ expect(result).toEqual(expected);
237
+ expect(mockRepo.findById).toHaveBeenCalledWith('1');
238
+ });
239
+
240
+ it('throws NotFoundError when user does not exist', async () => {
241
+ mockRepo.findById.mockResolvedValue(null);
242
+
243
+ await expect(userService.getUser('999'))
244
+ .rejects.toThrow(NotFoundError);
245
+ });
246
+ });
247
+ });
248
+ ```
249
+ }
250
+
251
+ Pytest {
252
+ ```python
253
+ # File structure
254
+ src/
255
+ services/
256
+ user_service.py
257
+ tests/
258
+ services/
259
+ test_user_service.py # Mirror structure
260
+
261
+ # conftest.py - Shared fixtures
262
+ import pytest
263
+ from unittest.mock import Mock
264
+
265
+ @pytest.fixture
266
+ def mock_user_repo():
267
+ return Mock(spec=UserRepository)
268
+
269
+ @pytest.fixture
270
+ def user_service(mock_user_repo):
271
+ return UserService(repository=mock_user_repo)
272
+
273
+ # test_user_service.py
274
+ class TestUserService:
275
+ def test_get_user_returns_user_when_found(
276
+ self, user_service, mock_user_repo
277
+ ):
278
+ expected = User(id="1", name="Alice")
279
+ mock_user_repo.find_by_id.return_value = expected
280
+
281
+ result = user_service.get_user("1")
282
+
283
+ assert result == expected
284
+ mock_user_repo.find_by_id.assert_called_once_with("1")
285
+
286
+ def test_get_user_raises_not_found_when_missing(
287
+ self, user_service, mock_user_repo
288
+ ):
289
+ mock_user_repo.find_by_id.return_value = None
290
+
291
+ with pytest.raises(NotFoundError):
292
+ user_service.get_user("999")
293
+
294
+ @pytest.mark.parametrize("invalid_email", [
295
+ "",
296
+ "no-at-sign",
297
+ "@no-local-part.com",
298
+ "no-domain@",
299
+ ])
300
+ def test_validate_email_rejects_invalid_formats(
301
+ self, user_service, invalid_email
302
+ ):
303
+ assert not user_service.validate_email(invalid_email)
304
+ ```
305
+ }
306
+
307
+ ReactTestingLibrary {
308
+ ```typescript
309
+ // Component test
310
+ import { render, screen, userEvent } from '@testing-library/react';
311
+ import { LoginForm } from './LoginForm';
312
+
313
+ describe('LoginForm', () => {
314
+ it('calls onSubmit with credentials when form is submitted', async () => {
315
+ const onSubmit = jest.fn();
316
+ const user = userEvent.setup();
317
+
318
+ render(<LoginForm onSubmit={onSubmit} />);
319
+
320
+ await user.type(screen.getByLabelText('Email'), 'test@example.com');
321
+ await user.type(screen.getByLabelText('Password'), 'secret123');
322
+ await user.click(screen.getByRole('button', { name: 'Sign In' }));
323
+
324
+ expect(onSubmit).toHaveBeenCalledWith({
325
+ email: 'test@example.com',
326
+ password: 'secret123',
327
+ });
328
+ });
329
+
330
+ it('displays validation error for invalid email', async () => {
331
+ const user = userEvent.setup();
332
+
333
+ render(<LoginForm onSubmit={jest.fn()} />);
334
+
335
+ await user.type(screen.getByLabelText('Email'), 'invalid');
336
+ await user.click(screen.getByRole('button', { name: 'Sign In' }));
337
+
338
+ expect(screen.getByText('Please enter a valid email')).toBeInTheDocument();
339
+ });
340
+ });
341
+ ```
342
+ }
343
+ }
344
+
345
+ TestOrganization {
346
+ FileNamingConventions {
347
+ | Framework | Test File Pattern | Example |
348
+ |-----------|------------------------|----------------------------|
349
+ | Jest | `*.test.ts` | `UserService.test.ts` |
350
+ | Pytest | `test_*.py` | `test_user_service.py` |
351
+ | Go | `*_test.go` | `user_service_test.go` |
352
+ | JUnit | `*Test.java` | `UserServiceTest.java` |
353
+ }
354
+
355
+ DirectoryStructurePatterns {
356
+ CoLocatedTests {
357
+ Preferred for unit tests:
358
+ ```
359
+ src/
360
+ services/
361
+ UserService.ts
362
+ UserService.test.ts
363
+ utils/
364
+ validators.ts
365
+ validators.test.ts
366
+ ```
367
+ }
368
+
369
+ SeparateTestDirectory {
370
+ For integration/E2E:
371
+ ```
372
+ src/
373
+ services/
374
+ UserService.ts
375
+ tests/
376
+ unit/
377
+ services/
378
+ UserService.test.ts
379
+ integration/
380
+ api/
381
+ users.test.ts
382
+ e2e/
383
+ user-registration.spec.ts
384
+ ```
385
+ }
386
+ }
387
+ }
388
+
389
+ BestPractices {
390
+ - Run tests before committing; never commit failing tests
391
+ - Keep unit tests under 100ms execution time
392
+ - Mock external dependencies at service boundaries only
393
+ - Use factories or fixtures for test data, not raw literals
394
+ - Delete flaky tests or fix them immediately
395
+ - Review tests during code review with same rigor as production code
396
+ - Name tests as specifications that document behavior
397
+ - Prefer real implementations over mocks when practical
398
+ - Test edge cases: nulls, empty collections, boundaries
399
+ - Avoid conditional logic in tests
400
+ }
401
+
402
+ AntiPatterns {
403
+ TestingImplementationDetails {
404
+ ```typescript
405
+ // WRONG: Brittle test that breaks on refactoring
406
+ it('stores user in _users array', () => {
407
+ const service = new UserService();
408
+ service.addUser(user);
409
+ expect(service._users).toContain(user);
410
+ });
411
+ ```
412
+ }
413
+
414
+ SharedMutableState {
415
+ ```python
416
+ # WRONG: Tests interfere with each other
417
+ users = []
418
+
419
+ def test_add_user():
420
+ users.append(User())
421
+
422
+ def test_user_count():
423
+ assert len(users) == 0 # Fails if test_add_user runs first
424
+ ```
425
+ }
426
+
427
+ OverMocking {
428
+ ```typescript
429
+ // WRONG: Mocking the system under test
430
+ it('processes payment', () => {
431
+ const processor = new PaymentProcessor();
432
+ jest.spyOn(processor, 'validate').mockReturnValue(true);
433
+ jest.spyOn(processor, 'charge').mockResolvedValue({ success: true });
434
+
435
+ // What are we even testing?
436
+ const result = processor.process(payment);
437
+ });
438
+ ```
439
+ }
440
+
441
+ TestDuplication {
442
+ ```python
443
+ # WRONG: Copy-paste tests with minor variations
444
+ def test_validate_email_empty():
445
+ assert not validate_email("")
446
+
447
+ def test_validate_email_no_at():
448
+ assert not validate_email("invalid")
449
+
450
+ def test_validate_email_no_domain():
451
+ assert not validate_email("user@")
452
+
453
+ # CORRECT: Parameterized test
454
+ @pytest.mark.parametrize("invalid_email", ["", "invalid", "user@"])
455
+ def test_validate_email_rejects_invalid_formats(invalid_email):
456
+ assert not validate_email(invalid_email)
457
+ ```
458
+ }
459
+ }
460
+ }
461
+
462
+ ## References
463
+
464
+ - `examples/test-pyramid.md` - Detailed test pyramid implementation guide with framework examples