Skip to content

Commit 101053b

Browse files
intel352claude
andcommitted
docs: add BDD/Gherkin support design for wftest
Pre-built godog step definitions, pipeline + scenario coverage, strict mode for CI, feature ↔ pipeline linking via @pipeline tags and implicit HTTP route matching. 3 implementation phases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3bb1144 commit 101053b

1 file changed

Lines changed: 232 additions & 0 deletions

File tree

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# wftest/bdd — Gherkin BDD Support for Workflow Testing
2+
3+
**Date:** 2026-03-23
4+
**Status:** Approved
5+
6+
## Overview
7+
8+
Add BDD/Gherkin support to the wftest integration test harness. Pre-built godog step definitions map Gherkin scenarios to wftest harness methods. Pipeline + scenario coverage reporting. Strict mode for CI enforcement of unimplemented features.
9+
10+
## Architecture
11+
12+
```
13+
wftest/bdd/
14+
├── steps.go # Pre-built godog step definitions
15+
├── context.go # BDD test context (wraps wftest.Harness per scenario)
16+
├── coverage.go # Pipeline + scenario coverage calculation
17+
├── strict.go # Undefined/pending step detection
18+
├── runner.go # RunFeatures(t, dir, opts...) integration point
19+
└── runner_test.go
20+
```
21+
22+
**Dependency:** `github.com/cucumber/godog v0.15.1` (same version as modular)
23+
24+
## Pre-Built Step Definitions
25+
26+
### Engine Setup
27+
28+
```gherkin
29+
Given the workflow engine is loaded with "config/app.yaml"
30+
Given the workflow engine is loaded with config:
31+
"""yaml
32+
pipelines:
33+
greet:
34+
steps:
35+
- name: say_hello
36+
type: step.set
37+
config:
38+
values:
39+
message: "hello"
40+
"""
41+
```
42+
43+
### Mocking
44+
45+
```gherkin
46+
Given step "step.db_query" is mocked to return:
47+
| key | value |
48+
| rows | [] |
49+
| count | 0 |
50+
Given step "step.db_query" returns JSON:
51+
"""json
52+
{"rows": [{"id": 1, "email": "test@example.com"}], "count": 1}
53+
"""
54+
Given module "database" "db" is mocked
55+
```
56+
57+
### HTTP Triggers
58+
59+
```gherkin
60+
When I POST "/api/v1/auth/register" with JSON:
61+
"""json
62+
{"email": "test@example.com", "password": "secret123"}
63+
"""
64+
When I GET "/api/v1/users/me" with header "Authorization" = "Bearer token123"
65+
When I PUT "/api/v1/users/123" with:
66+
| name | Updated Name |
67+
When I DELETE "/api/v1/items/456"
68+
```
69+
70+
### Pipeline Triggers
71+
72+
```gherkin
73+
When I execute pipeline "process-order" with:
74+
| order_id | 123 |
75+
| items | [a, b] |
76+
When I fire event "user.created" with:
77+
| user_id | 123 |
78+
When I fire schedule "daily-cleanup"
79+
```
80+
81+
### Response Assertions
82+
83+
```gherkin
84+
Then the response status should be 201
85+
Then the response body should contain "success"
86+
Then the response JSON "user.id" should not be empty
87+
Then the response JSON "error" should be "email required"
88+
Then the response header "Content-Type" should be "application/json"
89+
```
90+
91+
### Step Assertions
92+
93+
```gherkin
94+
Then step "insert_user" should have been executed
95+
Then step "send_email" should not have been executed
96+
Then step "calculate_damage" output "damage" should be 8
97+
Then step "insert_user" output "rows_affected" should be 1
98+
```
99+
100+
### State Assertions
101+
102+
```gherkin
103+
Given state "sessions" is seeded from "testdata/combat_setup.json"
104+
Given state "sessions" has key "game-1" with:
105+
| players | ["alice", "bob"] |
106+
| turn | alice |
107+
Then state "sessions" key "game-1" field "goblin_hp" should be 12
108+
Then state "sessions" key "game-1" field "turn" should be "bob"
109+
```
110+
111+
### Sequence (Multi-Step Stateful)
112+
113+
```gherkin
114+
Scenario: Full combat round
115+
Given the workflow engine is loaded with "config/app.yaml"
116+
And state "sessions" is seeded from "testdata/combat.json"
117+
118+
When I execute pipeline "attack" with:
119+
| game_id | game-1 |
120+
| attacker | warrior |
121+
| target | goblin |
122+
Then step "calculate_damage" output "damage" should be 8
123+
And state "sessions" key "game-1" field "goblin_hp" should be 12
124+
125+
When I execute pipeline "attack" with:
126+
| game_id | game-1 |
127+
| attacker | goblin |
128+
| target | warrior |
129+
Then state "sessions" key "game-1" field "warrior_hp" should be 27
130+
```
131+
132+
## Go Integration
133+
134+
```go
135+
func TestFeatures(t *testing.T) {
136+
bdd.RunFeatures(t, "features/",
137+
bdd.WithConfig("config/app.yaml"),
138+
bdd.WithMockStep("step.db_query", wftest.Returns(defaultDBResponse)),
139+
)
140+
}
141+
142+
func TestAuthFeatures(t *testing.T) {
143+
bdd.RunFeatures(t, "features/auth.feature",
144+
bdd.WithConfig("config/app.yaml"),
145+
)
146+
}
147+
```
148+
149+
## Coverage
150+
151+
### Pipeline Coverage
152+
153+
Scans app.yaml for all pipeline names, scans .feature files for pipeline references (explicit `@pipeline:name` tags + implicit HTTP route matching), reports gaps.
154+
155+
```
156+
$ wfctl test --coverage config/
157+
158+
Pipeline Coverage: 45/78 (57.7%)
159+
160+
COVERED:
161+
auth-register .............. auth.feature:12
162+
auth-login ................ auth.feature:28
163+
wishlist-create ........... wishlists.feature:5
164+
165+
UNCOVERED:
166+
payment-refund
167+
admin-dispute-update
168+
cron-expire-claims
169+
```
170+
171+
### Scenario Coverage
172+
173+
Counts total scenarios across .feature files, runs them, reports implementation status.
174+
175+
```
176+
Scenario Coverage:
177+
Total: 85 scenarios
178+
Implemented: 72 (84.7%)
179+
Passing: 70 (82.4%)
180+
Pending: 2 (2.4%)
181+
Undefined: 13 (15.3%)
182+
```
183+
184+
## Feature ↔ Pipeline Linking
185+
186+
Two methods:
187+
188+
**Explicit:** `@pipeline:name` tag on scenarios
189+
```gherkin
190+
@pipeline:auth-register
191+
Scenario: Successful registration
192+
When I POST "/api/v1/auth/register" with JSON:
193+
...
194+
```
195+
196+
**Implicit:** HTTP route matching — `POST /api/v1/auth/register` matched against pipeline trigger configs in app.yaml.
197+
198+
## Strict Mode
199+
200+
`wfctl test --strict` (or `bdd.RunFeatures(t, ..., bdd.Strict())`) fails on undefined/pending steps:
201+
202+
```
203+
$ wfctl test --strict features/
204+
205+
FAIL: 3 scenarios have undefined steps:
206+
auth.feature:23 - Given the user has MFA enabled
207+
payment.feature:45 - When the webhook signature is invalid
208+
admin.feature:12 - Then the audit log should contain an entry
209+
210+
Exit code: 1
211+
```
212+
213+
Default is lenient — undefined steps warn but don't fail. Allows incremental development.
214+
215+
## Implementation Phases
216+
217+
### Phase 1: Core BDD Runner + Step Definitions
218+
- wftest/bdd package with godog dependency
219+
- context.go — BDD context wrapping wftest.Harness
220+
- steps.go — all pre-built step definitions (engine setup, mocking, HTTP, pipeline, response, step, state assertions)
221+
- runner.go — RunFeatures(t, path, opts...)
222+
- Test with sample .feature file
223+
224+
### Phase 2: Coverage
225+
- coverage.go — pipeline coverage (scan app.yaml + feature files)
226+
- coverage.go — scenario coverage (count defined vs implemented vs passing)
227+
- wfctl test --coverage integration
228+
229+
### Phase 3: Strict Mode + CLI
230+
- strict.go — undefined/pending step detection
231+
- wfctl test --strict integration
232+
- Update docs/testing.md with BDD section

0 commit comments

Comments
 (0)