@comfanion/workflow 4.38.4-dev.1 → 4.39.0-dev.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 (37) hide show
  1. package/package.json +1 -1
  2. package/src/build-info.json +2 -2
  3. package/src/opencode/skills/acceptance-criteria/SKILL.md +58 -176
  4. package/src/opencode/skills/architecture-design/SKILL.md +86 -576
  5. package/src/opencode/skills/archiving/SKILL.md +60 -140
  6. package/src/opencode/skills/coding-standards/SKILL.md +113 -434
  7. package/src/opencode/skills/coding-standards/what-to-document.md +512 -0
  8. package/src/opencode/skills/database-design/SKILL.md +94 -778
  9. package/src/opencode/skills/database-design/indexing.md +187 -0
  10. package/src/opencode/skills/database-design/migrations.md +239 -0
  11. package/src/opencode/skills/database-design/schema-design.md +319 -0
  12. package/src/opencode/skills/doc-todo/SKILL.md +35 -27
  13. package/src/opencode/skills/epic-writing/SKILL.md +156 -244
  14. package/src/opencode/skills/epic-writing/template.md +11 -1
  15. package/src/opencode/skills/methodologies/SKILL.md +91 -354
  16. package/src/opencode/skills/methodologies/define.md +336 -0
  17. package/src/opencode/skills/methodologies/diagnose.md +374 -0
  18. package/src/opencode/skills/methodologies/empathize.md +253 -0
  19. package/src/opencode/skills/methodologies/ideate.md +458 -0
  20. package/src/opencode/skills/prd-writing/SKILL.md +162 -366
  21. package/src/opencode/skills/prd-writing/template.md +178 -48
  22. package/src/opencode/skills/requirements-gathering/SKILL.md +102 -117
  23. package/src/opencode/skills/requirements-gathering/template.md +97 -17
  24. package/src/opencode/skills/sprint-planning/SKILL.md +76 -225
  25. package/src/opencode/skills/sprint-planning/template.yaml +8 -0
  26. package/src/opencode/skills/story-writing/SKILL.md +76 -210
  27. package/src/opencode/skills/story-writing/template.md +10 -1
  28. package/src/opencode/skills/test-design/SKILL.md +78 -84
  29. package/src/opencode/skills/test-design/test-strategy.md +279 -0
  30. package/src/opencode/skills/test-design/unit-tests-mocking.md +247 -0
  31. package/src/opencode/skills/test-design/unit-tests-patterns.md +181 -0
  32. package/src/opencode/skills/test-design/unit-tests.md +117 -0
  33. package/src/opencode/skills/unit-writing/SKILL.md +119 -377
  34. package/src/opencode/skills/module-documentation/SKILL.md +0 -224
  35. package/src/opencode/skills/module-documentation/template.md +0 -139
  36. /package/src/opencode/skills/test-design/{template-integration.md → templates/template-integration.md} +0 -0
  37. /package/src/opencode/skills/test-design/{template-module.md → templates/template-module.md} +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: test-design
3
- description: Use when designing test strategy, writing unit/integration tests, or improving coverage
3
+ description: Design test strategy, write unit/integration/E2E tests, plan test coverage, and define testing approach. Use when designing tests, writing test cases, planning test coverage, or when user mentions "test design", "test strategy", "unit tests", "integration tests", "test coverage", or "testing approach".
4
4
  license: MIT
5
5
  compatibility: opencode
6
6
  metadata:
@@ -10,102 +10,96 @@ metadata:
10
10
 
11
11
  # Test Design Skill
12
12
 
13
- Principles for writing effective tests.
14
-
15
- ## Test Naming
16
-
13
+ ```xml
14
+ <test_design>
15
+ <definition>Design test strategy, write unit/integration/E2E tests</definition>
16
+
17
+ <test_types>
18
+ <unit>Individual components, fast, isolated → See [unit-tests.md](unit-tests.md)</unit>
19
+ <integration>Module contracts, API boundaries → See [integration-tests.md](integration-tests.md)</integration>
20
+ <e2e>User scenarios, critical paths → See [e2e-tests.md](e2e-tests.md)</e2e>
21
+ </test_types>
22
+
23
+ <test_pyramid>
24
+ <many>Unit tests (70-80% coverage)</many>
25
+ <some>Integration tests (50-60% coverage)</some>
26
+ <few>E2E tests (20-30% critical paths)</few>
27
+ </test_pyramid>
28
+
29
+ <quick_reference>
30
+ <what_to_test>Public API, Business logic, Error handling, Edge cases</what_to_test>
31
+ <what_not_to_test>Private methods, Getters/setters, Framework internals</what_not_to_test>
32
+ <naming>Test{Component}_{Method}_{Scenario}_{Expected}</naming>
33
+ <structure>AAA: Arrange → Act → Assert</structure>
34
+ </quick_reference>
35
+
36
+ <coverage_targets>
37
+ <domain>80%+</domain>
38
+ <application>70%+</application>
39
+ <infrastructure>50%+</infrastructure>
40
+ <focus>Critical paths, not 100%</focus>
41
+ </coverage_targets>
42
+
43
+ <when_to_test>
44
+ <tdd>Red → Green → Refactor (clear requirements)</tdd>
45
+ <after>Write code first (prototyping, unclear requirements)</after>
46
+ </when_to_test>
47
+ </test_design>
17
48
  ```
18
- Test{Component}_{Method}_{Scenario}_{Expected}
19
-
20
- Examples:
21
- - TestUser_Create_ValidData_Success
22
- - TestUser_Create_EmptyEmail_ReturnsError
23
- - TestOrder_Cancel_AlreadyShipped_Fails
24
- ```
25
-
26
- ## Test Structure (AAA)
27
49
 
28
- ```
29
- // Arrange - Setup
30
- input := ...
31
- expected := ...
50
+ ---
32
51
 
33
- // Act - Execute
34
- result := sut.Method(input)
52
+ ## Detailed Guides
35
53
 
36
- // Assert - Verify
37
- assert(result == expected)
38
- ```
54
+ **Unit Testing:**
55
+ - [unit-tests.md](unit-tests.md) - Basics: what to test, AAA pattern, naming
56
+ - [unit-tests-patterns.md](unit-tests-patterns.md) - Table-driven, state transitions, validation
57
+ - [unit-tests-mocking.md](unit-tests-mocking.md) - Mocking, DI, test isolation
39
58
 
40
- ## Table-Driven Tests
59
+ **Integration Testing:**
60
+ - [integration-tests.md](integration-tests.md) - Module contracts, API boundaries, events
41
61
 
42
- When testing multiple scenarios of same function:
62
+ **E2E Testing:**
63
+ - [e2e-tests.md](e2e-tests.md) - User scenarios, critical paths, smoke tests
43
64
 
44
- ```
45
- tests := []struct {
46
- name string
47
- input Input
48
- expected Output
49
- wantErr bool
50
- }{
51
- {"valid input", validInput(), expectedOutput(), false},
52
- {"empty input", emptyInput(), nil, true},
53
- }
54
-
55
- for _, tt := range tests {
56
- t.Run(tt.name, func(t *testing.T) {
57
- result, err := sut.Method(tt.input)
58
- // assert
59
- })
60
- }
61
- ```
65
+ **Strategy:**
66
+ - [test-strategy.md](test-strategy.md) - Test pyramid, coverage targets, when to use what
62
67
 
63
- ## What to Test
68
+ **Templates:**
69
+ - [templates/template-integration.md](templates/template-integration.md) - Architecture integration tests
70
+ - [templates/template-module.md](templates/template-module.md) - Module test cases
64
71
 
65
- **Always test:**
66
- - Public API / exported functions
67
- - Business logic / domain rules
68
- - Error handling paths
69
- - Edge cases (empty, nil, zero, max)
70
- - State transitions
72
+ ---
71
73
 
72
- **Skip testing:**
73
- - Private implementation details
74
- - Simple getters/setters
75
- - Generated code
76
- - Framework internals
74
+ ## Quick Example
75
+
76
+ ```typescript
77
+ // Unit test
78
+ it('calculates order total', () => {
79
+ const order = new Order();
80
+ order.addItem({ price: 100, quantity: 2 });
81
+ expect(order.calculateTotal()).toBe(200);
82
+ });
83
+
84
+ // Integration test
85
+ it('saves order to database', async () => {
86
+ const order = await orderService.create(orderData);
87
+ const saved = await db.orders.findById(order.id);
88
+ expect(saved).toMatchObject(orderData);
89
+ });
90
+ ```
77
91
 
78
- ## Mocking
92
+ ---
79
93
 
80
- Mock when:
81
- - External services (HTTP, DB)
82
- - Non-deterministic (time, random)
83
- - Slow operations
94
+ ## Test Pyramid
84
95
 
85
- Prefer interfaces for testability:
86
96
  ```
87
- type Repository interface {
88
- Find(id string) (*Entity, error)
89
- }
90
-
91
- // Production: RealRepository
92
- // Tests: MockRepository
97
+ /\
98
+ / \ E2E (Few)
99
+ /____\
100
+ / \ Integration (Some)
101
+ / \
102
+ /__________\ Unit (Many)
93
103
  ```
94
104
 
95
- ## Test Isolation
96
-
97
- Each test should:
98
- - Setup its own data
99
- - Not depend on other tests
100
- - Clean up after itself
101
- - Run in any order
102
-
103
- ## Coverage Guidelines
104
-
105
- | Layer | Target |
106
- |-------|--------|
107
- | Domain/Business | 80%+ |
108
- | Application/UseCase | 70%+ |
109
- | Infrastructure | 50%+ |
110
-
111
- Focus on critical paths, not 100% coverage.
105
+ For full details, see the guides above.
@@ -0,0 +1,279 @@
1
+ # Test Strategy
2
+
3
+ When to use which type of test and how much coverage.
4
+
5
+ ## Test Pyramid
6
+
7
+ ```
8
+ /\
9
+ / \ E2E (Few)
10
+ /____\ - User scenarios
11
+ / \ - Critical paths
12
+ / \
13
+ /__________\ Integration (Some)
14
+ / \ - Module contracts
15
+ / \- API boundaries
16
+ /________________\ Unit (Many)
17
+ - Business logic
18
+ - Fast, isolated
19
+ ```
20
+
21
+ **Principle:** More unit tests, fewer E2E tests.
22
+
23
+ ---
24
+
25
+ ## Test Types
26
+
27
+ ### Unit Tests
28
+ **What:** Individual components in isolation
29
+ **When:** Business logic, calculations, validations
30
+ **Speed:** Fast (milliseconds)
31
+ **Coverage:** 70-80%
32
+
33
+ **Example:**
34
+ ```typescript
35
+ it('calculates order total', () => {
36
+ const order = new Order();
37
+ order.addItem({ price: 100, quantity: 2 });
38
+ expect(order.calculateTotal()).toBe(200);
39
+ });
40
+ ```
41
+
42
+ ### Integration Tests
43
+ **What:** Multiple components working together
44
+ **When:** Module boundaries, API contracts, DB operations
45
+ **Speed:** Medium (seconds)
46
+ **Coverage:** 50-60%
47
+
48
+ **Example:**
49
+ ```typescript
50
+ it('creates order in database', async () => {
51
+ const order = await orderService.create(orderData);
52
+ const saved = await db.orders.findById(order.id);
53
+ expect(saved).toMatchObject(orderData);
54
+ });
55
+ ```
56
+
57
+ ### E2E Tests
58
+ **What:** Complete user scenarios
59
+ **When:** Critical user flows, smoke tests
60
+ **Speed:** Slow (minutes)
61
+ **Coverage:** 20-30% of critical paths
62
+
63
+ **Example:**
64
+ ```typescript
65
+ it('user can place order', async () => {
66
+ await page.goto('/products');
67
+ await page.click('[data-testid="add-to-cart"]');
68
+ await page.click('[data-testid="checkout"]');
69
+ await page.fill('[name="email"]', 'test@example.com');
70
+ await page.click('[data-testid="place-order"]');
71
+ await expect(page.locator('.success')).toBeVisible();
72
+ });
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Coverage Targets
78
+
79
+ ### By Layer
80
+
81
+ | Layer | Target | Focus |
82
+ |-------|--------|-------|
83
+ | **Domain** | 80%+ | Business rules, state transitions |
84
+ | **Application** | 70%+ | Use cases, orchestration |
85
+ | **Infrastructure** | 50%+ | Adapters, repositories |
86
+ | **API** | 60%+ | Endpoints, validation |
87
+ | **UI** | 40%+ | Critical user flows |
88
+
89
+ ### By Project Size
90
+
91
+ | Size | Unit | Integration | E2E |
92
+ |------|------|-------------|-----|
93
+ | **TOY** | 60%+ | 30%+ | 10%+ |
94
+ | **SMALL** | 70%+ | 40%+ | 20%+ |
95
+ | **MEDIUM** | 75%+ | 50%+ | 25%+ |
96
+ | **LARGE** | 80%+ | 60%+ | 30%+ |
97
+
98
+ **Don't chase 100%** - Focus on critical paths.
99
+
100
+ ---
101
+
102
+ ## What to Test at Each Level
103
+
104
+ ### Unit Tests
105
+ ✅ **Test:**
106
+ - Business logic
107
+ - Calculations
108
+ - Validations
109
+ - State transitions
110
+ - Error handling
111
+
112
+ ❌ **Don't test:**
113
+ - Private methods
114
+ - Getters/setters
115
+ - Framework code
116
+
117
+ ### Integration Tests
118
+ ✅ **Test:**
119
+ - Module contracts
120
+ - API boundaries
121
+ - Database operations
122
+ - Event publishing/consuming
123
+ - External service calls
124
+
125
+ ❌ **Don't test:**
126
+ - Business logic (unit test it)
127
+ - UI rendering (E2E test it)
128
+
129
+ ### E2E Tests
130
+ ✅ **Test:**
131
+ - Critical user flows
132
+ - Happy paths
133
+ - Smoke tests
134
+ - Cross-browser (if needed)
135
+
136
+ ❌ **Don't test:**
137
+ - Edge cases (unit test them)
138
+ - Error scenarios (integration test them)
139
+ - Every feature (too slow)
140
+
141
+ ---
142
+
143
+ ## When to Write Tests
144
+
145
+ ### TDD (Test-Driven Development)
146
+ **Process:** Red → Green → Refactor
147
+
148
+ 1. **Red:** Write failing test
149
+ 2. **Green:** Make it pass (simplest way)
150
+ 3. **Refactor:** Improve code
151
+
152
+ **When to use:**
153
+ - Clear requirements
154
+ - Complex business logic
155
+ - API design
156
+ - Bug fixes
157
+
158
+ **Example:**
159
+ ```typescript
160
+ // 1. Red - write failing test
161
+ it('calculates discount', () => {
162
+ expect(calculateDiscount(100, 0.1)).toBe(10);
163
+ });
164
+
165
+ // 2. Green - make it pass
166
+ function calculateDiscount(price, rate) {
167
+ return price * rate;
168
+ }
169
+
170
+ // 3. Refactor - improve
171
+ function calculateDiscount(price: number, rate: number): number {
172
+ if (rate < 0 || rate > 1) throw new Error('Invalid rate');
173
+ return price * rate;
174
+ }
175
+ ```
176
+
177
+ ### Test After
178
+ Write code first, then tests.
179
+
180
+ **When to use:**
181
+ - Prototyping
182
+ - Unclear requirements
183
+ - Exploratory coding
184
+ - Spikes
185
+
186
+ ---
187
+
188
+ ## Cost vs Benefit
189
+
190
+ ### High Value Tests
191
+ - Critical business logic
192
+ - Payment processing
193
+ - Security features
194
+ - Data integrity
195
+ - User authentication
196
+
197
+ ### Medium Value Tests
198
+ - Standard CRUD operations
199
+ - Common workflows
200
+ - API endpoints
201
+ - Form validation
202
+
203
+ ### Low Value Tests
204
+ - Simple getters/setters
205
+ - Configuration loading
206
+ - Trivial formatting
207
+ - Pass-through methods
208
+
209
+ **Focus on high-value tests first.**
210
+
211
+ ---
212
+
213
+ ## Test Maintenance
214
+
215
+ ### Keep Tests Green
216
+ - Fix failing tests immediately
217
+ - Don't skip tests
218
+ - Don't comment out tests
219
+
220
+ ### Refactor Tests
221
+ - DRY (helper functions)
222
+ - Clear names
223
+ - Remove obsolete tests
224
+
225
+ ### Fast Feedback
226
+ - Run unit tests on save
227
+ - Run integration tests on commit
228
+ - Run E2E tests on PR
229
+
230
+ ---
231
+
232
+ ## CI/CD Integration
233
+
234
+ ```yaml
235
+ # Example CI pipeline
236
+ stages:
237
+ - lint
238
+ - unit-tests # Fast (1-2 min)
239
+ - integration # Medium (5-10 min)
240
+ - e2e # Slow (15-30 min)
241
+ - deploy
242
+
243
+ unit-tests:
244
+ script: npm test
245
+ coverage: 80%
246
+
247
+ integration:
248
+ script: npm run test:integration
249
+ coverage: 50%
250
+
251
+ e2e:
252
+ script: npm run test:e2e
253
+ only: [main, develop]
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Tips
259
+
260
+ **Start with unit tests:**
261
+ - Fastest feedback
262
+ - Easiest to write
263
+ - Most coverage
264
+
265
+ **Add integration tests for boundaries:**
266
+ - Module contracts
267
+ - API endpoints
268
+ - Database operations
269
+
270
+ **E2E tests for critical flows:**
271
+ - User registration
272
+ - Checkout
273
+ - Payment
274
+ - Core features
275
+
276
+ **Measure what matters:**
277
+ - Coverage is a guide, not a goal
278
+ - Focus on critical paths
279
+ - Test behavior, not implementation
@@ -0,0 +1,247 @@
1
+ # Mocking and Test Isolation
2
+
3
+ How to mock dependencies and isolate tests.
4
+
5
+ ## When to Mock
6
+
7
+ **✅ Mock these:**
8
+ - External services (HTTP, DB)
9
+ - Non-deterministic (time, random)
10
+ - Slow operations (file I/O, network)
11
+ - Dependencies you don't control
12
+
13
+ **❌ Don't mock these:**
14
+ - Simple value objects
15
+ - Pure functions
16
+ - Your own domain logic
17
+
18
+ ---
19
+
20
+ ## Dependency Injection
21
+
22
+ Make code testable by injecting dependencies.
23
+
24
+ **Bad (hardcoded):**
25
+ ```typescript
26
+ class OrderService {
27
+ async createOrder(data: OrderData) {
28
+ const db = new Database(); // hardcoded!
29
+ return db.save(data);
30
+ }
31
+ }
32
+ ```
33
+
34
+ **Good (injected):**
35
+ ```typescript
36
+ class OrderService {
37
+ constructor(private db: Database) {}
38
+
39
+ async createOrder(data: OrderData) {
40
+ return this.db.save(data);
41
+ }
42
+ }
43
+
44
+ // Test
45
+ it('saves order', async () => {
46
+ const mockDb = { save: jest.fn().mockResolvedValue({ id: '123' }) };
47
+ const service = new OrderService(mockDb);
48
+
49
+ await service.createOrder(orderData);
50
+
51
+ expect(mockDb.save).toHaveBeenCalledWith(orderData);
52
+ });
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Interface-Based Mocking (Go)
58
+
59
+ ```go
60
+ // Interface
61
+ type Database interface {
62
+ Save(order Order) error
63
+ }
64
+
65
+ // Real implementation
66
+ type PostgresDB struct {}
67
+ func (db *PostgresDB) Save(order Order) error { /* ... */ }
68
+
69
+ // Mock for tests
70
+ type MockDB struct {
71
+ SaveFunc func(Order) error
72
+ }
73
+ func (m *MockDB) Save(order Order) error {
74
+ return m.SaveFunc(order)
75
+ }
76
+
77
+ // Test
78
+ func TestOrderService_CreateOrder(t *testing.T) {
79
+ mockDB := &MockDB{
80
+ SaveFunc: func(o Order) error {
81
+ return nil // success
82
+ },
83
+ }
84
+
85
+ service := NewOrderService(mockDB)
86
+ err := service.CreateOrder(order)
87
+
88
+ assert.NoError(t, err)
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Mock Frameworks
95
+
96
+ ### TypeScript (Jest)
97
+
98
+ ```typescript
99
+ // Mock function
100
+ const mockSave = jest.fn();
101
+
102
+ // Mock return value
103
+ mockSave.mockResolvedValue({ id: '123' });
104
+
105
+ // Mock error
106
+ mockSave.mockRejectedValue(new Error('DB error'));
107
+
108
+ // Verify calls
109
+ expect(mockSave).toHaveBeenCalledWith(orderData);
110
+ expect(mockSave).toHaveBeenCalledTimes(1);
111
+ ```
112
+
113
+ ### Python (unittest.mock)
114
+
115
+ ```python
116
+ from unittest.mock import Mock, patch
117
+
118
+ # Mock object
119
+ mock_db = Mock()
120
+ mock_db.save.return_value = {'id': '123'}
121
+
122
+ # Verify calls
123
+ mock_db.save.assert_called_once_with(order_data)
124
+
125
+ # Patch dependency
126
+ @patch('module.Database')
127
+ def test_create_order(mock_db_class):
128
+ mock_db = mock_db_class.return_value
129
+ mock_db.save.return_value = {'id': '123'}
130
+ # test code
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Test Isolation
136
+
137
+ **Rules:**
138
+
139
+ 1. **Setup own data** - Don't depend on other tests
140
+ 2. **No shared state** - Each test is independent
141
+ 3. **Clean up** - Reset state after test
142
+ 4. **Run in any order** - No execution dependencies
143
+
144
+ **Example:**
145
+
146
+ ```typescript
147
+ describe('OrderRepository', () => {
148
+ let repository: OrderRepository;
149
+ let db: TestDatabase;
150
+
151
+ beforeEach(async () => {
152
+ // Fresh database for each test
153
+ db = await TestDatabase.create();
154
+ repository = new OrderRepository(db);
155
+ });
156
+
157
+ afterEach(async () => {
158
+ // Clean up after each test
159
+ await db.destroy();
160
+ });
161
+
162
+ it('saves order', async () => {
163
+ const order = createTestOrder();
164
+ await repository.save(order);
165
+ // Independent of other tests
166
+ });
167
+ });
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Test Doubles
173
+
174
+ ### Stub
175
+ Returns predefined values.
176
+
177
+ ```typescript
178
+ const stub = {
179
+ getPrice: () => 100 // always returns 100
180
+ };
181
+ ```
182
+
183
+ ### Mock
184
+ Records calls for verification.
185
+
186
+ ```typescript
187
+ const mock = {
188
+ save: jest.fn().mockResolvedValue({ id: '123' })
189
+ };
190
+
191
+ // Later verify
192
+ expect(mock.save).toHaveBeenCalledWith(data);
193
+ ```
194
+
195
+ ### Spy
196
+ Wraps real object, records calls.
197
+
198
+ ```typescript
199
+ const realService = new OrderService();
200
+ const spy = jest.spyOn(realService, 'createOrder');
201
+
202
+ await realService.createOrder(data);
203
+
204
+ expect(spy).toHaveBeenCalled();
205
+ ```
206
+
207
+ ### Fake
208
+ Working implementation (simplified).
209
+
210
+ ```typescript
211
+ class FakeDatabase implements Database {
212
+ private data = new Map();
213
+
214
+ async save(order: Order) {
215
+ this.data.set(order.id, order);
216
+ return order;
217
+ }
218
+
219
+ async find(id: string) {
220
+ return this.data.get(id);
221
+ }
222
+ }
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Tips
228
+
229
+ **Prefer fakes over mocks:**
230
+ - Fakes are more realistic
231
+ - Less brittle tests
232
+ - Easier to maintain
233
+
234
+ **Keep mocks simple:**
235
+ - Mock only what you need
236
+ - Don't over-specify
237
+ - Focus on behavior
238
+
239
+ **Avoid mock hell:**
240
+ - Too many mocks = bad design
241
+ - Consider refactoring
242
+ - Use real objects when possible
243
+
244
+ **Test isolation:**
245
+ - Each test is independent
246
+ - No shared state
247
+ - Clean up after yourself