Only the Test button turned Space into Enter; Save, Revert and the buttons of the dialogs ignored it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019reK4DUGYqDUjniWYJvwUW
172 lines
5.0 KiB
Go
172 lines
5.0 KiB
Go
package ui
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
)
|
|
|
|
func TestArrowNavigation(t *testing.T) {
|
|
f := tview.NewForm().
|
|
AddDropDown("A", []string{"x", "y", "z"}, 0, nil).
|
|
AddCheckbox("B", true, nil).
|
|
AddButton("Add", nil).AddButton("Cancel", nil)
|
|
arrowNavigation(f, nil, nil)
|
|
var focus func(p tview.Primitive)
|
|
focus = func(p tview.Primitive) { p.Focus(focus) }
|
|
f.Focus(focus)
|
|
cap := f.GetInputCapture()
|
|
send := func(key tcell.Key) { cap(tcell.NewEventKey(key, 0, 0)) }
|
|
|
|
dd := f.GetFormItem(0).(*tview.DropDown)
|
|
send(tcell.KeyRight)
|
|
if i, _ := dd.GetCurrentOption(); i != 1 {
|
|
t.Fatalf("Right: option %d, want 1", i)
|
|
}
|
|
send(tcell.KeyLeft)
|
|
send(tcell.KeyLeft)
|
|
if i, _ := dd.GetCurrentOption(); i != 2 {
|
|
t.Fatalf("Left wraps: option %d, want 2", i)
|
|
}
|
|
send(tcell.KeyDown)
|
|
if item, _ := f.GetFocusedItemIndex(); item != 1 {
|
|
t.Fatalf("Down: item %d, want 1", item)
|
|
}
|
|
send(tcell.KeyDown)
|
|
send(tcell.KeyDown)
|
|
send(tcell.KeyDown) // clamps at the last button
|
|
if _, b := f.GetFocusedItemIndex(); b != 1 {
|
|
t.Fatalf("button %d, want 1", b)
|
|
}
|
|
send(tcell.KeyLeft)
|
|
if _, b := f.GetFocusedItemIndex(); b != 0 {
|
|
t.Fatalf("Left on buttons: %d, want 0", b)
|
|
}
|
|
send(tcell.KeyUp)
|
|
if item, _ := f.GetFocusedItemIndex(); item != 1 {
|
|
t.Fatalf("Up from first button: item %d, want 1", item)
|
|
}
|
|
|
|
// Space on a button is Enter; on a checkbox it stays Space.
|
|
send(tcell.KeyDown)
|
|
if got := cap(tcell.NewEventKey(tcell.KeyRune, ' ', 0)); got == nil || got.Key() != tcell.KeyEnter {
|
|
t.Errorf("Space on a button: %v", got)
|
|
}
|
|
send(tcell.KeyUp)
|
|
if got := cap(tcell.NewEventKey(tcell.KeyRune, ' ', 0)); got == nil || got.Key() != tcell.KeyRune {
|
|
t.Errorf("Space on a checkbox: %v", got)
|
|
}
|
|
}
|
|
|
|
func TestSearchNowFollowsMonitored(t *testing.T) {
|
|
f := tview.NewForm().
|
|
AddDropDown("P", []string{"a"}, 0, nil).
|
|
AddDropDown("R", []string{"a"}, 0, nil).
|
|
AddCheckbox("M", true, nil).
|
|
AddCheckbox("S", true, nil).
|
|
AddButton("Add", nil)
|
|
arrowNavigation(f, nil, nil)
|
|
var focus func(p tview.Primitive)
|
|
focus = func(p tview.Primitive) { p.Focus(focus) }
|
|
f.Focus(focus)
|
|
|
|
mon := f.GetFormItem(2).(*tview.Checkbox)
|
|
search := f.GetFormItem(3).(*tview.Checkbox)
|
|
blocked := 0
|
|
sync := bindSearchNow(search, mon.IsChecked, func() { blocked++ })
|
|
mon.SetChangedFunc(func(bool) { sync() })
|
|
|
|
cap := f.GetInputCapture()
|
|
key := func(k tcell.Key) { cap(tcell.NewEventKey(k, 0, 0)) }
|
|
space := func(item tview.FormItem) {
|
|
item.InputHandler()(tcell.NewEventKey(tcell.KeyRune, ' ', 0), func(tview.Primitive) {})
|
|
}
|
|
focused := func() (n int) {
|
|
for i := 0; i < f.GetFormItemCount(); i++ {
|
|
if f.GetFormItem(i).HasFocus() {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
key(tcell.KeyDown)
|
|
key(tcell.KeyDown) // on "Monitored"
|
|
space(mon) // unmonitor
|
|
if search.IsChecked() {
|
|
t.Error("Search now must be unchecked when not monitored")
|
|
}
|
|
key(tcell.KeyUp)
|
|
if n := focused(); n != 1 {
|
|
t.Fatalf("%d fields have focus after moving up, want 1", n)
|
|
}
|
|
if item, _ := f.GetFocusedItemIndex(); item != 1 {
|
|
t.Errorf("focus on item %d, want 1", item)
|
|
}
|
|
|
|
key(tcell.KeyDown)
|
|
key(tcell.KeyDown) // on "Search now"
|
|
space(search)
|
|
if search.IsChecked() || blocked != 1 {
|
|
t.Errorf("ticking while blocked: checked=%v blocked=%d", search.IsChecked(), blocked)
|
|
}
|
|
|
|
key(tcell.KeyUp)
|
|
space(mon) // monitor again
|
|
if !search.IsChecked() {
|
|
t.Error("Search now should return to its previous choice")
|
|
}
|
|
}
|
|
|
|
func TestBrowseOpenDropDown(t *testing.T) {
|
|
f := tview.NewForm().AddDropDown("D", []string{"any", "a", "b", "c"}, 0, nil)
|
|
var seen []int
|
|
aborted, cancelled := 0, 0
|
|
arrowNavigation(f, func() { cancelled++ }, &browseHooks{
|
|
browse: func(_ *tview.DropDown, i int) { seen = append(seen, i) },
|
|
abort: func() { aborted++ },
|
|
})
|
|
var focus func(p tview.Primitive)
|
|
focus = func(p tview.Primitive) { p.Focus(focus) }
|
|
f.Focus(focus)
|
|
send := func(k tcell.Key) { f.InputHandler()(tcell.NewEventKey(k, 0, 0), focus) }
|
|
dd := f.GetFormItem(0).(*tview.DropDown)
|
|
|
|
send(tcell.KeyEnter) // open
|
|
if !dd.IsOpen() {
|
|
t.Fatal("dropdown did not open")
|
|
}
|
|
send(tcell.KeyDown)
|
|
send(tcell.KeyDown)
|
|
send(tcell.KeyUp)
|
|
send(tcell.KeyUp)
|
|
send(tcell.KeyUp) // wraps to the last entry
|
|
if want := []int{1, 2, 1, 0, 3}; !reflect.DeepEqual(seen, want) {
|
|
t.Fatalf("browse saw %v, want %v", seen, want)
|
|
}
|
|
send(tcell.KeyEnter) // select what the highlight is on
|
|
if i, _ := dd.GetCurrentOption(); i != 3 {
|
|
t.Errorf("selected option %d, want 3: the mirrored highlight drifted from the real list", i)
|
|
}
|
|
|
|
seen = nil
|
|
send(tcell.KeyEnter)
|
|
send(tcell.KeyDown) // wraps to 0
|
|
send(tcell.KeyEscape)
|
|
if cancelled != 0 {
|
|
t.Error("Esc on an open list must only close the list")
|
|
}
|
|
send(tcell.KeyEscape) // list closed: now Esc cancels the form
|
|
if cancelled != 1 {
|
|
t.Errorf("cancelled=%d, want 1", cancelled)
|
|
}
|
|
if aborted != 1 || !reflect.DeepEqual(seen, []int{0}) {
|
|
t.Errorf("aborted=%d seen=%v", aborted, seen)
|
|
}
|
|
if i, _ := dd.GetCurrentOption(); i != 3 {
|
|
t.Errorf("Esc must keep the committed option, got %d", i)
|
|
}
|
|
}
|