diff --git a/internal/iostreams/forms.go b/internal/iostreams/forms.go index 532a521b..42e2228d 100644 --- a/internal/iostreams/forms.go +++ b/internal/iostreams/forms.go @@ -82,8 +82,12 @@ func inputForm(io *IOStreams, _ context.Context, message string, cfg InputPrompt // buildConfirmForm constructs an interactive form for yes/no confirmation prompts. func buildConfirmForm(io *IOStreams, message string, choice *bool) *huh.Form { - field := huh.NewConfirm(). + field := huh.NewSelect[bool](). Title(message). + Options( + huh.NewOption("Yes", true), + huh.NewOption("No", false), + ). Value(choice) return newForm(io, field) } diff --git a/internal/iostreams/forms_test.go b/internal/iostreams/forms_test.go index 721d4e6c..e42f80df 100644 --- a/internal/iostreams/forms_test.go +++ b/internal/iostreams/forms_test.go @@ -105,26 +105,36 @@ func TestConfirmForm(t *testing.T) { assert.Contains(t, view, "No") }) - t.Run("default value is respected", func(t *testing.T) { + t.Run("default true starts on Yes", func(t *testing.T) { choice := true f := buildConfirmForm(nil, "Continue?", &choice) f.Update(f.Init()) - assert.True(t, choice) + view := ansi.Strip(f.View()) + assert.Contains(t, view, style.Chevron()+" Yes") }) - t.Run("toggle changes value", func(t *testing.T) { + t.Run("default false starts on No", func(t *testing.T) { choice := false f := buildConfirmForm(nil, "Continue?", &choice) f.Update(f.Init()) - // Toggle to Yes - f.Update(tea.KeyPressMsg{Code: tea.KeyLeft}) - assert.True(t, choice) + view := ansi.Strip(f.View()) + assert.Contains(t, view, style.Chevron()+" No") + }) + + t.Run("arrow keys change selection", func(t *testing.T) { + choice := true + f := buildConfirmForm(nil, "Continue?", &choice) + f.Update(f.Init()) - // Toggle back to No - f.Update(tea.KeyPressMsg{Code: tea.KeyRight}) + // Move down to No + f.Update(tea.KeyPressMsg{Code: tea.KeyDown}) assert.False(t, choice) + + // Move back up to Yes + f.Update(tea.KeyPressMsg{Code: tea.KeyUp}) + assert.True(t, choice) }) } @@ -450,12 +460,12 @@ func TestFormsAccessible(t *testing.T) { assert.Contains(t, out.String(), "Pick one (press Enter for 1)") }) - t.Run("confirm form accepts yes/no input", func(t *testing.T) { + t.Run("confirm form accepts numbered input", func(t *testing.T) { var choice bool f := buildConfirmForm(io, "Continue?", &choice) var out strings.Builder - err := f.WithOutput(&out).WithInput(strings.NewReader("y\n")).Run() + err := f.WithOutput(&out).WithInput(strings.NewReader("1\n")).Run() assert.NoError(t, err) assert.True(t, choice)