@windyroad/tdd 0.4.3-preview.565 → 0.4.4-preview.576
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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +14 -0
- package/hooks/lib/tdd-gate.sh +23 -0
- package/hooks/test/tdd-gate.bats +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,20 @@ Once active, the workflow is enforced on every edit:
|
|
|
49
49
|
|
|
50
50
|
Test files and config/doc files are always writable regardless of state.
|
|
51
51
|
|
|
52
|
+
## Supported test layouts
|
|
53
|
+
|
|
54
|
+
The hook associates an implementation file with its tracked test by matching one of the following path shapes (per [P201](../../docs/problems/verifying/201-windyroad-tdd-hook-only-recognises-same-dir-or-tests-test-associations.md)):
|
|
55
|
+
|
|
56
|
+
| Shape | Impl path | Test path |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| Same-directory | `src/foo.js` | `src/foo.test.js` or `src/foo.spec.js` |
|
|
59
|
+
| `__tests__/`-adjacent | `src/foo.js` | `src/__tests__/foo.test.js` |
|
|
60
|
+
| Parent `__tests__/` | `src/components/Hero.tsx` | `src/__tests__/Hero.test.tsx` |
|
|
61
|
+
| `test/`-mirror (Vitest default; many Jest setups) | `src/foo.js`, `src/a/b/foo.js`, `packages/<pkg>/src/foo.js` | `test/foo.test.js`, `test/a/b/foo.test.js`, `packages/<pkg>/test/foo.test.js` |
|
|
62
|
+
| Cucumber step-definitions | `features/step_definitions/checkout.steps.js` | `features/checkout.feature` |
|
|
63
|
+
|
|
64
|
+
The `test/`-mirror rule replaces the **last** `src` path segment with `test`, so it works at any nesting depth and for monorepo workspace layouts.
|
|
65
|
+
|
|
52
66
|
## How It Works
|
|
53
67
|
|
|
54
68
|
| Hook | Trigger | What it does |
|
package/hooks/lib/tdd-gate.sh
CHANGED
|
@@ -157,6 +157,22 @@ tdd_find_test_for_impl() {
|
|
|
157
157
|
return
|
|
158
158
|
fi
|
|
159
159
|
|
|
160
|
+
# test/-mirror layout (P201): src/foo.js → test/foo.test.js, recursive for
|
|
161
|
+
# nested src/a/b/foo.js → test/a/b/foo.test.js, and workspace
|
|
162
|
+
# packages/<pkg>/src/foo.js → packages/<pkg>/test/foo.test.js.
|
|
163
|
+
# Compute the mirror once — depends only on DIR (the impl's directory).
|
|
164
|
+
# Replaces the LAST `src` path segment with `test`.
|
|
165
|
+
local MIRROR_DIR=""
|
|
166
|
+
case "$DIR" in
|
|
167
|
+
src) MIRROR_DIR="test" ;;
|
|
168
|
+
src/*) MIRROR_DIR="test/${DIR#src/}" ;;
|
|
169
|
+
*/src) MIRROR_DIR="${DIR%/src}/test" ;;
|
|
170
|
+
*/src/*)
|
|
171
|
+
local _mirror_prefix="${DIR%/src/*}"
|
|
172
|
+
MIRROR_DIR="${_mirror_prefix}/test/${DIR#"${_mirror_prefix}"/src/}"
|
|
173
|
+
;;
|
|
174
|
+
esac
|
|
175
|
+
|
|
160
176
|
# Check tracked test files for a match
|
|
161
177
|
# Priority: exact match in tracked files (any convention)
|
|
162
178
|
while IFS= read -r tracked; do
|
|
@@ -188,6 +204,13 @@ tdd_find_test_for_impl() {
|
|
|
188
204
|
;;
|
|
189
205
|
esac
|
|
190
206
|
|
|
207
|
+
# test/-mirror layout (P201): match when tracked_dir is the computed mirror
|
|
208
|
+
if [ -n "$MIRROR_DIR" ] && [ "$tracked_dir" = "$MIRROR_DIR" ]; then
|
|
209
|
+
case "$tracked_base" in
|
|
210
|
+
"${STEM}.test."*|"${STEM}.spec."*) echo "$tracked"; return ;;
|
|
211
|
+
esac
|
|
212
|
+
fi
|
|
213
|
+
|
|
191
214
|
# Cucumber: features/step_definitions/foo.steps.js → features/foo.feature
|
|
192
215
|
# If this impl is inside a step_definitions/ directory, look in the parent for a .feature file
|
|
193
216
|
case "$DIR" in
|
package/hooks/test/tdd-gate.bats
CHANGED
|
@@ -238,6 +238,61 @@ teardown() {
|
|
|
238
238
|
[ -z "$result" ]
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
# --- tdd_find_test_for_impl: test/-mirror layout (P201) ---
|
|
242
|
+
# Vitest default + many Jest setups mirror src/ under a sibling test/ tree.
|
|
243
|
+
# A new behavioural rule: replace the LAST `src` path segment with `test`
|
|
244
|
+
# to map an impl path to its mirrored test directory.
|
|
245
|
+
|
|
246
|
+
@test "find_test_for_impl: test/-mirror at top level (src/foo.js → test/foo.test.js)" {
|
|
247
|
+
tdd_add_test_file "$TEST_SESSION" "test/foo.test.js"
|
|
248
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "src/foo.js")
|
|
249
|
+
[ "$result" = "test/foo.test.js" ]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@test "find_test_for_impl: test/-mirror with .spec variant (src/foo.js → test/foo.spec.js)" {
|
|
253
|
+
tdd_add_test_file "$TEST_SESSION" "test/foo.spec.js"
|
|
254
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "src/foo.js")
|
|
255
|
+
[ "$result" = "test/foo.spec.js" ]
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@test "find_test_for_impl: test/-mirror preserves .tsx (src/Hero.tsx → test/Hero.test.tsx)" {
|
|
259
|
+
tdd_add_test_file "$TEST_SESSION" "test/Hero.test.tsx"
|
|
260
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "src/Hero.tsx")
|
|
261
|
+
[ "$result" = "test/Hero.test.tsx" ]
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@test "find_test_for_impl: test/-mirror recursive nested (src/a/b/foo.js → test/a/b/foo.test.js)" {
|
|
265
|
+
tdd_add_test_file "$TEST_SESSION" "test/a/b/foo.test.js"
|
|
266
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "src/a/b/foo.js")
|
|
267
|
+
[ "$result" = "test/a/b/foo.test.js" ]
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@test "find_test_for_impl: test/-mirror workspace layout (packages/foo/src/x.ts → packages/foo/test/x.test.ts)" {
|
|
271
|
+
tdd_add_test_file "$TEST_SESSION" "packages/foo/test/x.test.ts"
|
|
272
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "packages/foo/src/x.ts")
|
|
273
|
+
[ "$result" = "packages/foo/test/x.test.ts" ]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@test "find_test_for_impl: test/-mirror workspace nested (packages/foo/src/a/b/x.ts → packages/foo/test/a/b/x.test.ts)" {
|
|
277
|
+
tdd_add_test_file "$TEST_SESSION" "packages/foo/test/a/b/x.test.ts"
|
|
278
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "packages/foo/src/a/b/x.ts")
|
|
279
|
+
[ "$result" = "packages/foo/test/a/b/x.test.ts" ]
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@test "find_test_for_impl: test/-mirror does NOT match wrong stem (src/foo.js + test/bar.test.js → empty)" {
|
|
283
|
+
tdd_add_test_file "$TEST_SESSION" "test/bar.test.js"
|
|
284
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "src/foo.js")
|
|
285
|
+
[ -z "$result" ]
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
@test "find_test_for_impl: test/-mirror does NOT match without src/ anchor (lib/foo.js + test/foo.test.js → empty)" {
|
|
289
|
+
# Ticket scope is explicitly src/-anchored mirror; lib/foo.js → test/foo.test.js
|
|
290
|
+
# is NOT a recognised pairing (the ticket frames it as "src/foo.js → test/foo.test.js").
|
|
291
|
+
tdd_add_test_file "$TEST_SESSION" "test/foo.test.js"
|
|
292
|
+
result=$(tdd_find_test_for_impl "$TEST_SESSION" "lib/foo.js")
|
|
293
|
+
[ -z "$result" ]
|
|
294
|
+
}
|
|
295
|
+
|
|
241
296
|
# --- State for impl files (via association) ---
|
|
242
297
|
|
|
243
298
|
@test "read_state_for_impl: returns IDLE when no associated test" {
|