@@ -160,39 +160,240 @@ setup() {
160160
161161# ── fzf interactive picker ───────────────────────────────────────────────────
162162
163- @test "bash output includes fzf picker for cd with no args" {
163+ # ── fzf: general setup ──────────────────────────────────────────────────────
164+
165+ @test "bash output includes fzf detection for cd with no args" {
164166 run cmd_init bash
165167 [ "$status" -eq 0 ]
166168 [[ "$output" == *"command -v fzf"* ]]
167169 [[ "$output" == *"--prompt=' Worktree> ' "* ]]
168170 [[ "$output" == *"--with-nth=2"* ]]
169- [[ "$output" == *"ctrl-e:execute"* ]]
170171}
171172
172- @test "zsh output includes fzf picker for cd with no args" {
173+ @test "zsh output includes fzf detection for cd with no args" {
173174 run cmd_init zsh
174175 [ "$status" -eq 0 ]
175176 [[ "$output" == *"command -v fzf"* ]]
176177 [[ "$output" == *"--prompt=' Worktree> ' "* ]]
177178 [[ "$output" == *"--with-nth=2"* ]]
178- [[ "$output" == *"ctrl-e:execute"* ]]
179179}
180180
181- @test "fish output includes fzf picker for cd with no args" {
181+ @test "fish output includes fzf detection for cd with no args" {
182182 run cmd_init fish
183183 [ "$status" -eq 0 ]
184184 [[ "$output" == *"type -q fzf"* ]]
185185 [[ "$output" == *"--prompt=' Worktree> ' "* ]]
186186 [[ "$output" == *"--with-nth=2"* ]]
187- [[ "$output" == *"ctrl-e:execute"* ]]
188187}
189188
189+ # ── fzf: header shows all keybindings ───────────────────────────────────────
190+
191+ @test "bash fzf header lists all keybindings" {
192+ run cmd_init bash
193+ [ "$status" -eq 0 ]
194+ [[ "$output" == *"enter:cd"* ]]
195+ [[ "$output" == *"ctrl-e:editor"* ]]
196+ [[ "$output" == *"ctrl-a:ai"* ]]
197+ [[ "$output" == *"ctrl-d:delete"* ]]
198+ [[ "$output" == *"ctrl-y:copy"* ]]
199+ [[ "$output" == *"ctrl-r:refresh"* ]]
200+ }
201+
202+ @test "zsh fzf header lists all keybindings" {
203+ run cmd_init zsh
204+ [ "$status" -eq 0 ]
205+ [[ "$output" == *"enter:cd"* ]]
206+ [[ "$output" == *"ctrl-e:editor"* ]]
207+ [[ "$output" == *"ctrl-a:ai"* ]]
208+ [[ "$output" == *"ctrl-d:delete"* ]]
209+ [[ "$output" == *"ctrl-y:copy"* ]]
210+ [[ "$output" == *"ctrl-r:refresh"* ]]
211+ }
212+
213+ @test "fish fzf header lists all keybindings" {
214+ run cmd_init fish
215+ [ "$status" -eq 0 ]
216+ [[ "$output" == *"enter:cd"* ]]
217+ [[ "$output" == *"ctrl-e:editor"* ]]
218+ [[ "$output" == *"ctrl-a:ai"* ]]
219+ [[ "$output" == *"ctrl-d:delete"* ]]
220+ [[ "$output" == *"ctrl-y:copy"* ]]
221+ [[ "$output" == *"ctrl-r:refresh"* ]]
222+ }
223+
224+ # ── fzf: enter (cd) ─────────────────────────────────────────────────────────
225+
226+ @test "bash fzf enter extracts path from selection field 1 and cd" {
227+ run cmd_init bash
228+ [ "$status" -eq 0 ]
229+ # Selection is parsed with cut -f1 to get path, then cd
230+ [[ "$output" == *' cut -f1' * ]]
231+ [[ "$output" == *' cd " $dir " ' * ]]
232+ }
233+
234+ @test "zsh fzf enter extracts path from selection field 1 and cd" {
235+ run cmd_init zsh
236+ [ "$status" -eq 0 ]
237+ [[ "$output" == *' cut -f1' * ]]
238+ [[ "$output" == *' cd " $dir " ' * ]]
239+ }
240+
241+ @test "fish fzf enter extracts path from selection and cd" {
242+ run cmd_init fish
243+ [ "$status" -eq 0 ]
244+ # Fish uses string split or cut to extract path
245+ [[ "$output" == *' cd ' * ]]
246+ }
247+
248+ # ── fzf: ctrl-e (editor) — via --expect ──────────────────────────────────────
249+
250+ @test "bash fzf ctrl-e handled via --expect for full terminal access" {
251+ run cmd_init bash
252+ [ "$status" -eq 0 ]
253+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
254+ [[ "$output" == *' git gtr editor' * ]]
255+ }
256+
257+ @test "zsh fzf ctrl-e handled via --expect for full terminal access" {
258+ run cmd_init zsh
259+ [ "$status" -eq 0 ]
260+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
261+ [[ "$output" == *' git gtr editor' * ]]
262+ }
263+
264+ @test "fish fzf ctrl-e handled via --expect for full terminal access" {
265+ run cmd_init fish
266+ [ "$status" -eq 0 ]
267+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
268+ [[ "$output" == *' git gtr editor' * ]]
269+ }
270+
271+ # ── fzf: ctrl-a (ai) — via --expect ─────────────────────────────────────────
272+
273+ @test "bash fzf ctrl-a runs git gtr ai after fzf exits" {
274+ run cmd_init bash
275+ [ "$status" -eq 0 ]
276+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
277+ [[ "$output" == *' git gtr ai' * ]]
278+ }
279+
280+ @test "zsh fzf ctrl-a runs git gtr ai after fzf exits" {
281+ run cmd_init zsh
282+ [ "$status" -eq 0 ]
283+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
284+ [[ "$output" == *' git gtr ai' * ]]
285+ }
286+
287+ @test "fish fzf ctrl-a runs git gtr ai after fzf exits" {
288+ run cmd_init fish
289+ [ "$status" -eq 0 ]
290+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
291+ [[ "$output" == *' git gtr ai' * ]]
292+ }
293+
294+ # ── fzf: ctrl-d (delete + reload) ───────────────────────────────────────────
295+
296+ @test "bash fzf ctrl-d runs git gtr rm and reloads list" {
297+ run cmd_init bash
298+ [ "$status" -eq 0 ]
299+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
300+ }
301+
302+ @test "zsh fzf ctrl-d runs git gtr rm and reloads list" {
303+ run cmd_init zsh
304+ [ "$status" -eq 0 ]
305+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
306+ }
307+
308+ @test "fish fzf ctrl-d runs git gtr rm and reloads list" {
309+ run cmd_init fish
310+ [ "$status" -eq 0 ]
311+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
312+ }
313+
314+ # ── fzf: ctrl-y (copy) ──────────────────────────────────────────────────────
315+
316+ @test "bash fzf ctrl-y runs git gtr copy on selected branch" {
317+ run cmd_init bash
318+ [ "$status" -eq 0 ]
319+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
320+ }
321+
322+ @test "zsh fzf ctrl-y runs git gtr copy on selected branch" {
323+ run cmd_init zsh
324+ [ "$status" -eq 0 ]
325+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
326+ }
327+
328+ @test "fish fzf ctrl-y runs git gtr copy on selected branch" {
329+ run cmd_init fish
330+ [ "$status" -eq 0 ]
331+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
332+ }
333+
334+ # ── fzf: ctrl-r (refresh) ───────────────────────────────────────────────────
335+
336+ @test "bash fzf ctrl-r reloads worktree list" {
337+ run cmd_init bash
338+ [ "$status" -eq 0 ]
339+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
340+ }
341+
342+ @test "zsh fzf ctrl-r reloads worktree list" {
343+ run cmd_init zsh
344+ [ "$status" -eq 0 ]
345+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
346+ }
347+
348+ @test "fish fzf ctrl-r reloads worktree list" {
349+ run cmd_init fish
350+ [ "$status" -eq 0 ]
351+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
352+ }
353+
354+ # ── fzf: preview window ─────────────────────────────────────────────────────
355+
356+ @test "bash fzf preview shows git log and status" {
357+ run cmd_init bash
358+ [ "$status" -eq 0 ]
359+ [[ "$output" == *"--preview="* ]]
360+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
361+ [[ "$output" == *"git -C {1} status --short"* ]]
362+ [[ "$output" == *"--preview-window=right:50%"* ]]
363+ }
364+
365+ @test "zsh fzf preview shows git log and status" {
366+ run cmd_init zsh
367+ [ "$status" -eq 0 ]
368+ [[ "$output" == *"--preview="* ]]
369+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
370+ [[ "$output" == *"git -C {1} status --short"* ]]
371+ [[ "$output" == *"--preview-window=right:50%"* ]]
372+ }
373+
374+ @test "fish fzf preview shows git log and status" {
375+ run cmd_init fish
376+ [ "$status" -eq 0 ]
377+ [[ "$output" == *"--preview="* ]]
378+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
379+ [[ "$output" == *"git -C {1} status --short"* ]]
380+ [[ "$output" == *"--preview-window=right:50%"* ]]
381+ }
382+
383+ # ── fzf: fallback messages ──────────────────────────────────────────────────
384+
190385@test "bash output shows fzf install hint when no args and no fzf" {
191386 run cmd_init bash
192387 [ "$status" -eq 0 ]
193388 [[ "$output" == *' Install fzf for an interactive picker' * ]]
194389}
195390
391+ @test "zsh output shows fzf install hint when no args and no fzf" {
392+ run cmd_init zsh
393+ [ "$status" -eq 0 ]
394+ [[ "$output" == *' Install fzf for an interactive picker' * ]]
395+ }
396+
196397@test "fish output shows fzf install hint when no args and no fzf" {
197398 run cmd_init fish
198399 [ "$status" -eq 0 ]
0 commit comments