@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.
@@ -101,5 +101,5 @@
101
101
  }
102
102
  },
103
103
  "name": "wr-tdd",
104
- "version": "0.4.3"
104
+ "version": "0.4.4"
105
105
  }
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 |
@@ -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
@@ -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" {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/tdd",
3
- "version": "0.4.3-preview.565",
3
+ "version": "0.4.4-preview.576",
4
4
  "description": "TDD state machine enforcement (Red-Green-Refactor cycle)",
5
5
  "bin": {
6
6
  "windyroad-tdd": "./bin/install.mjs"