@comfanion/workflow 4.36.59 → 4.36.60

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/build-info.json +2 -2
  3. package/src/opencode/agents/analyst.md +6 -18
  4. package/src/opencode/agents/architect.md +5 -21
  5. package/src/opencode/agents/coder.md +8 -13
  6. package/src/opencode/agents/crawler.md +38 -38
  7. package/src/opencode/agents/dev.md +1 -62
  8. package/src/opencode/agents/pm.md +9 -25
  9. package/src/opencode/agents/researcher.md +1 -6
  10. package/src/opencode/agents/reviewer.md +26 -29
  11. package/src/opencode/commands/dev-story.md +2 -1
  12. package/src/opencode/skills/acceptance-criteria/SKILL.md +1 -1
  13. package/src/opencode/skills/archiving/SKILL.md +7 -18
  14. package/src/opencode/skills/changelog/SKILL.md +1 -1
  15. package/src/opencode/skills/code-review/SKILL.md +2 -3
  16. package/src/opencode/skills/coding-standards/SKILL.md +8 -18
  17. package/src/opencode/skills/dev-story/SKILL.md +69 -543
  18. package/src/opencode/skills/doc-todo/SKILL.md +22 -313
  19. package/src/opencode/skills/epic-writing/SKILL.md +1 -1
  20. package/src/opencode/skills/jira-integration/SKILL.md +1 -1
  21. package/src/opencode/skills/methodologies/SKILL.md +1 -1
  22. package/src/opencode/skills/module-documentation/SKILL.md +1 -1
  23. package/src/opencode/skills/prd-validation/SKILL.md +1 -1
  24. package/src/opencode/skills/prd-writing/SKILL.md +1 -1
  25. package/src/opencode/skills/requirements-gathering/SKILL.md +1 -1
  26. package/src/opencode/skills/requirements-validation/SKILL.md +1 -1
  27. package/src/opencode/skills/research-methodology/SKILL.md +1 -1
  28. package/src/opencode/skills/story-writing/SKILL.md +1 -1
  29. package/src/opencode/skills/test-design/SKILL.md +63 -275
  30. package/src/opencode/skills/translation/SKILL.md +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: test-design
3
- description: How to design and write effective tests for implementations
3
+ description: Use when designing test strategy, writing unit/integration tests, or improving coverage
4
4
  license: MIT
5
5
  compatibility: opencode
6
6
  metadata:
@@ -10,314 +10,102 @@ metadata:
10
10
 
11
11
  # Test Design Skill
12
12
 
13
- How to design and write effective tests for implementations.
13
+ Principles for writing effective tests.
14
14
 
15
- ## Test Pyramid
15
+ ## Test Naming
16
16
 
17
17
  ```
18
- /\
19
- / \ E2E Tests (few)
20
- /----\
21
- / \ Integration Tests (some)
22
- /--------\
23
- / \ Unit Tests (many)
24
- /------------\
25
- ```
26
-
27
- ## Unit Tests
28
-
29
- ### When to Write
30
- - Every public function
31
- - Every method with business logic
32
- - Edge cases and error paths
33
-
34
- ### Structure (Arrange-Act-Assert)
18
+ Test{Component}_{Method}_{Scenario}_{Expected}
35
19
 
36
- ```go
37
- func TestFunction_Scenario_ExpectedBehavior(t *testing.T) {
38
- // Arrange - Setup test data
39
- input := createTestInput()
40
- expected := expectedOutput()
41
- sut := NewSystemUnderTest()
42
-
43
- // Act - Execute the function
44
- result, err := sut.Function(input)
45
-
46
- // Assert - Verify the outcome
47
- if err != nil {
48
- t.Fatalf("unexpected error: %v", err)
49
- }
50
- if result != expected {
51
- t.Errorf("got %v, want %v", result, expected)
52
- }
53
- }
20
+ Examples:
21
+ - TestUser_Create_ValidData_Success
22
+ - TestUser_Create_EmptyEmail_ReturnsError
23
+ - TestOrder_Cancel_AlreadyShipped_Fails
54
24
  ```
55
25
 
56
- ### Naming Convention
57
-
58
- ```
59
- Test{Type}_{Method}_{Scenario}
26
+ ## Test Structure (AAA)
60
27
 
61
- Examples:
62
- - TestOffer_UpdatePrice_Success
63
- - TestOffer_UpdatePrice_NegativePrice_ReturnsError
64
- - TestOffer_Activate_FromPendingStatus_Success
65
- - TestOffer_Activate_FromDeclinedStatus_Fails
66
28
  ```
29
+ // Arrange - Setup
30
+ input := ...
31
+ expected := ...
67
32
 
68
- ### Table-Driven Tests
33
+ // Act - Execute
34
+ result := sut.Method(input)
69
35
 
70
- ```go
71
- func TestOffer_Validate(t *testing.T) {
72
- tests := []struct {
73
- name string
74
- offer Offer
75
- wantErr bool
76
- }{
77
- {
78
- name: "valid offer",
79
- offer: validOffer(),
80
- wantErr: false,
81
- },
82
- {
83
- name: "zero price",
84
- offer: offerWithZeroPrice(),
85
- wantErr: true,
86
- },
87
- {
88
- name: "negative quantity",
89
- offer: offerWithNegativeQty(),
90
- wantErr: true,
91
- },
92
- }
93
-
94
- for _, tt := range tests {
95
- t.Run(tt.name, func(t *testing.T) {
96
- err := tt.offer.Validate()
97
- if (err != nil) != tt.wantErr {
98
- t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
99
- }
100
- })
101
- }
102
- }
36
+ // Assert - Verify
37
+ assert(result == expected)
103
38
  ```
104
39
 
105
- ## Integration Tests
106
-
107
- ### When to Write
108
- - Repository implementations
109
- - API endpoints
110
- - External service integrations
111
- - Multi-component workflows
40
+ ## Table-Driven Tests
112
41
 
113
- ### Setup/Teardown
42
+ When testing multiple scenarios of same function:
114
43
 
115
- ```go
116
- func TestMain(m *testing.M) {
117
- // Setup
118
- testDB = setupTestDatabase()
119
-
120
- // Run tests
121
- code := m.Run()
122
-
123
- // Teardown
124
- teardownTestDatabase(testDB)
125
-
126
- os.Exit(code)
127
- }
128
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
+ }
129
54
 
130
- ### Test Isolation
131
-
132
- ```go
133
- func TestRepository_Save(t *testing.T) {
134
- // Use transaction that rolls back
135
- tx := testDB.Begin()
136
- defer tx.Rollback()
137
-
138
- repo := NewRepository(tx)
139
-
140
- // Test code here
55
+ for _, tt := range tests {
56
+ t.Run(tt.name, func(t *testing.T) {
57
+ result, err := sut.Method(tt.input)
58
+ // assert
59
+ })
141
60
  }
142
61
  ```
143
62
 
144
- ## Test Coverage Requirements
145
-
146
- | Type | Minimum Coverage |
147
- |------|-----------------|
148
- | Domain/Business Logic | 80%+ |
149
- | Use Cases/Handlers | 70%+ |
150
- | Repositories | 60%+ |
151
- | HTTP Handlers | 50%+ |
152
-
153
63
  ## What to Test
154
64
 
155
- ### Domain Layer
156
- - All aggregate methods
157
- - All value object validation
158
- - Domain service logic
65
+ **Always test:**
66
+ - Public API / exported functions
67
+ - Business logic / domain rules
68
+ - Error handling paths
69
+ - Edge cases (empty, nil, zero, max)
159
70
  - State transitions
160
71
 
161
- ### Application Layer
162
- - Use case happy paths
163
- - Error scenarios
164
- - Validation failures
165
- - Authorization checks
166
-
167
- ### Infrastructure Layer
168
- - Repository CRUD operations
169
- - External service adapters
170
- - Event publishing/consuming
171
-
172
- ## What NOT to Test
173
-
174
- - Private functions (test via public interface)
72
+ **Skip testing:**
73
+ - Private implementation details
175
74
  - Simple getters/setters
176
- - Framework code
177
- - Generated code (SQLC, etc.)
75
+ - Generated code
76
+ - Framework internals
178
77
 
179
78
  ## Mocking
180
79
 
181
- ### When to Mock
182
- - External services
183
- - Databases (for unit tests)
184
- - Time-dependent operations
185
- - Random/non-deterministic operations
186
-
187
- ### Interface-Based Mocking
188
-
189
- ```go
190
- // Define interface
191
- type UserRepository interface {
192
- FindByID(ctx context.Context, id string) (*User, error)
193
- }
194
-
195
- // Create mock
196
- type MockUserRepository struct {
197
- FindByIDFunc func(ctx context.Context, id string) (*User, error)
198
- }
199
-
200
- func (m *MockUserRepository) FindByID(ctx context.Context, id string) (*User, error) {
201
- return m.FindByIDFunc(ctx, id)
202
- }
203
-
204
- // Use in test
205
- func TestUseCase(t *testing.T) {
206
- mockRepo := &MockUserRepository{
207
- FindByIDFunc: func(ctx context.Context, id string) (*User, error) {
208
- return &User{ID: id, Name: "Test"}, nil
209
- },
210
- }
211
-
212
- useCase := NewUseCase(mockRepo)
213
- // ...
214
- }
215
- ```
216
-
217
- ## Test Data
218
-
219
- ### Builders
220
-
221
- ```go
222
- func NewTestOffer() *Offer {
223
- return &Offer{
224
- ID: NewOfferID(),
225
- MerchantID: NewMerchantID(),
226
- Price: decimal.NewFromInt(100),
227
- Status: OfferStatusPending,
228
- }
229
- }
230
-
231
- func (o *Offer) WithPrice(price decimal.Decimal) *Offer {
232
- o.Price = price
233
- return o
234
- }
235
-
236
- func (o *Offer) WithStatus(status OfferStatus) *Offer {
237
- o.Status = status
238
- return o
239
- }
240
-
241
- // Usage
242
- offer := NewTestOffer().WithPrice(decimal.NewFromInt(200)).WithStatus(OfferStatusActive)
243
- ```
244
-
245
- ## Red-Green-Refactor Cycle
246
-
247
- ### 1. RED - Write Failing Test
248
-
249
- ```go
250
- func TestOffer_UpdatePrice_Success(t *testing.T) {
251
- offer := NewTestOffer()
252
- newPrice := decimal.NewFromInt(150)
253
-
254
- err := offer.UpdatePrice(newPrice)
255
-
256
- if err != nil {
257
- t.Fatalf("unexpected error: %v", err)
258
- }
259
- if !offer.Price.Equal(newPrice) {
260
- t.Errorf("price not updated")
261
- }
262
- }
263
- ```
264
-
265
- Run test - it should FAIL.
266
-
267
- ### 2. GREEN - Minimal Implementation
80
+ Mock when:
81
+ - External services (HTTP, DB)
82
+ - Non-deterministic (time, random)
83
+ - Slow operations
268
84
 
269
- ```go
270
- func (o *Offer) UpdatePrice(price decimal.Decimal) error {
271
- o.Price = price
272
- return nil
273
- }
85
+ Prefer interfaces for testability:
274
86
  ```
275
-
276
- Run test - it should PASS.
277
-
278
- ### 3. REFACTOR - Improve Code
279
-
280
- ```go
281
- func (o *Offer) UpdatePrice(price decimal.Decimal) error {
282
- if price.LessThanOrEqual(decimal.Zero) {
283
- return ErrInvalidPrice
284
- }
285
- o.Price = price
286
- return nil
87
+ type Repository interface {
88
+ Find(id string) (*Entity, error)
287
89
  }
288
- ```
289
-
290
- Run test - it should still PASS.
291
-
292
- Add test for new validation:
293
90
 
294
- ```go
295
- func TestOffer_UpdatePrice_ZeroPrice_ReturnsError(t *testing.T) {
296
- offer := NewTestOffer()
297
-
298
- err := offer.UpdatePrice(decimal.Zero)
299
-
300
- if !errors.Is(err, ErrInvalidPrice) {
301
- t.Errorf("expected ErrInvalidPrice, got %v", err)
302
- }
303
- }
91
+ // Production: RealRepository
92
+ // Tests: MockRepository
304
93
  ```
305
94
 
306
- ## Test Commands
307
-
308
- ```bash
309
- # Run all tests
310
- go test ./...
95
+ ## Test Isolation
311
96
 
312
- # Run with coverage
313
- go test -cover ./...
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
314
102
 
315
- # Run specific test
316
- go test -run TestOffer_UpdatePrice ./...
103
+ ## Coverage Guidelines
317
104
 
318
- # Run with race detection
319
- go test -race ./...
105
+ | Layer | Target |
106
+ |-------|--------|
107
+ | Domain/Business | 80%+ |
108
+ | Application/UseCase | 70%+ |
109
+ | Infrastructure | 50%+ |
320
110
 
321
- # Verbose output
322
- go test -v ./...
323
- ```
111
+ Focus on critical paths, not 100% coverage.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: translation
3
- description: Translate technical docs to user language, export to Confluence format
3
+ description: Use when translating docs to user language or exporting to Confluence format
4
4
  license: MIT
5
5
  compatibility: opencode
6
6
  metadata: