@@ -160,39 +160,242 @@ 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 to extract path, then cd
245+ [[ "$output" == *' string split' * ]]
246+ [[ "$output" == *' set dir' * ]]
247+ [[ "$output" == *' cd $dir ' * ]]
248+ }
249+
250+ # ── fzf: ctrl-e (editor) — via --expect ──────────────────────────────────────
251+
252+ @test "bash fzf ctrl-e handled via --expect for full terminal access" {
253+ run cmd_init bash
254+ [ "$status" -eq 0 ]
255+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
256+ [[ "$output" == *' git gtr editor' * ]]
257+ }
258+
259+ @test "zsh fzf ctrl-e handled via --expect for full terminal access" {
260+ run cmd_init zsh
261+ [ "$status" -eq 0 ]
262+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
263+ [[ "$output" == *' git gtr editor' * ]]
264+ }
265+
266+ @test "fish fzf ctrl-e handled via --expect for full terminal access" {
267+ run cmd_init fish
268+ [ "$status" -eq 0 ]
269+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
270+ [[ "$output" == *' git gtr editor' * ]]
271+ }
272+
273+ # ── fzf: ctrl-a (ai) — via --expect ─────────────────────────────────────────
274+
275+ @test "bash fzf ctrl-a runs git gtr ai after fzf exits" {
276+ run cmd_init bash
277+ [ "$status" -eq 0 ]
278+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
279+ [[ "$output" == *' git gtr ai' * ]]
280+ }
281+
282+ @test "zsh fzf ctrl-a runs git gtr ai after fzf exits" {
283+ run cmd_init zsh
284+ [ "$status" -eq 0 ]
285+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
286+ [[ "$output" == *' git gtr ai' * ]]
287+ }
288+
289+ @test "fish fzf ctrl-a runs git gtr ai after fzf exits" {
290+ run cmd_init fish
291+ [ "$status" -eq 0 ]
292+ [[ "$output" == *"--expect=ctrl-a,ctrl-e"* ]]
293+ [[ "$output" == *' git gtr ai' * ]]
294+ }
295+
296+ # ── fzf: ctrl-d (delete + reload) ───────────────────────────────────────────
297+
298+ @test "bash fzf ctrl-d runs git gtr rm and reloads list" {
299+ run cmd_init bash
300+ [ "$status" -eq 0 ]
301+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
302+ }
303+
304+ @test "zsh fzf ctrl-d runs git gtr rm and reloads list" {
305+ run cmd_init zsh
306+ [ "$status" -eq 0 ]
307+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
308+ }
309+
310+ @test "fish fzf ctrl-d runs git gtr rm and reloads list" {
311+ run cmd_init fish
312+ [ "$status" -eq 0 ]
313+ [[ "$output" == *"ctrl-d:execute(git gtr rm {2} > /dev/tty 2>&1 < /dev/tty)+reload(git gtr list --porcelain)"* ]]
314+ }
315+
316+ # ── fzf: ctrl-y (copy) ──────────────────────────────────────────────────────
317+
318+ @test "bash fzf ctrl-y runs git gtr copy on selected branch" {
319+ run cmd_init bash
320+ [ "$status" -eq 0 ]
321+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
322+ }
323+
324+ @test "zsh fzf ctrl-y runs git gtr copy on selected branch" {
325+ run cmd_init zsh
326+ [ "$status" -eq 0 ]
327+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
328+ }
329+
330+ @test "fish fzf ctrl-y runs git gtr copy on selected branch" {
331+ run cmd_init fish
332+ [ "$status" -eq 0 ]
333+ [[ "$output" == *"ctrl-y:execute(git gtr copy {2} > /dev/tty 2>&1 < /dev/tty)"* ]]
334+ }
335+
336+ # ── fzf: ctrl-r (refresh) ───────────────────────────────────────────────────
337+
338+ @test "bash fzf ctrl-r reloads worktree list" {
339+ run cmd_init bash
340+ [ "$status" -eq 0 ]
341+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
342+ }
343+
344+ @test "zsh fzf ctrl-r reloads worktree list" {
345+ run cmd_init zsh
346+ [ "$status" -eq 0 ]
347+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
348+ }
349+
350+ @test "fish fzf ctrl-r reloads worktree list" {
351+ run cmd_init fish
352+ [ "$status" -eq 0 ]
353+ [[ "$output" == *"ctrl-r:reload(git gtr list --porcelain)"* ]]
354+ }
355+
356+ # ── fzf: preview window ─────────────────────────────────────────────────────
357+
358+ @test "bash fzf preview shows git log and status" {
359+ run cmd_init bash
360+ [ "$status" -eq 0 ]
361+ [[ "$output" == *"--preview="* ]]
362+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
363+ [[ "$output" == *"git -C {1} status --short"* ]]
364+ [[ "$output" == *"--preview-window=right:50%"* ]]
365+ }
366+
367+ @test "zsh fzf preview shows git log and status" {
368+ run cmd_init zsh
369+ [ "$status" -eq 0 ]
370+ [[ "$output" == *"--preview="* ]]
371+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
372+ [[ "$output" == *"git -C {1} status --short"* ]]
373+ [[ "$output" == *"--preview-window=right:50%"* ]]
374+ }
375+
376+ @test "fish fzf preview shows git log and status" {
377+ run cmd_init fish
378+ [ "$status" -eq 0 ]
379+ [[ "$output" == *"--preview="* ]]
380+ [[ "$output" == *"git -C {1} log --oneline --graph --color=always"* ]]
381+ [[ "$output" == *"git -C {1} status --short"* ]]
382+ [[ "$output" == *"--preview-window=right:50%"* ]]
383+ }
384+
385+ # ── fzf: fallback messages ──────────────────────────────────────────────────
386+
190387@test "bash output shows fzf install hint when no args and no fzf" {
191388 run cmd_init bash
192389 [ "$status" -eq 0 ]
193390 [[ "$output" == *' Install fzf for an interactive picker' * ]]
194391}
195392
393+ @test "zsh output shows fzf install hint when no args and no fzf" {
394+ run cmd_init zsh
395+ [ "$status" -eq 0 ]
396+ [[ "$output" == *' Install fzf for an interactive picker' * ]]
397+ }
398+
196399@test "fish output shows fzf install hint when no args and no fzf" {
197400 run cmd_init fish
198401 [ "$status" -eq 0 ]
0 commit comments