@@ -29,6 +29,8 @@ func step(m Model, msg tea.Msg) Model {
2929
3030func keyType (t tea.KeyType ) tea.KeyMsg { return tea.KeyMsg {Type : t } }
3131
32+ func keyRune (r rune ) tea.KeyMsg { return tea.KeyMsg {Type : tea .KeyRunes , Runes : []rune {r }} }
33+
3234func space () tea.KeyMsg { return tea.KeyMsg {Type : tea .KeySpace } }
3335
3436func TestNew_DefaultsSelectAll (t * testing.T ) {
@@ -124,19 +126,32 @@ func TestSelect_Viewport(t *testing.T) {
124126 assert .Contains (t , view , "more" )
125127}
126128
127- func TestSelect_ArrowDirection (t * testing.T ) {
128- m := New (baseOptions ()) // cursor starts at the top of the stack (index 2)
129- assert .Equal (t , 2 , m .cursor )
130-
131- // "up" moves toward the top of the stack and is clamped there.
132- m = step (m , keyType (tea .KeyUp ))
133- assert .Equal (t , 2 , m .cursor )
129+ func TestSelect_NavigationDirection (t * testing.T ) {
130+ tests := []struct {
131+ name string
132+ up tea.KeyMsg
133+ down tea.KeyMsg
134+ }{
135+ {name : "arrow keys" , up : keyType (tea .KeyUp ), down : keyType (tea .KeyDown )},
136+ {name : "vim keys" , up : keyRune ('k' ), down : keyRune ('j' )},
137+ }
134138
135- // "down" moves toward the bottom of the stack (lower index).
136- m = step (m , keyType (tea .KeyDown ))
137- assert .Equal (t , 1 , m .cursor )
138- m = step (m , keyType (tea .KeyUp ))
139- assert .Equal (t , 2 , m .cursor )
139+ for _ , tt := range tests {
140+ t .Run (tt .name , func (t * testing.T ) {
141+ m := New (baseOptions ()) // cursor starts at the top of the stack (index 2)
142+ assert .Equal (t , 2 , m .cursor )
143+
144+ // Up moves toward the top of the stack and is clamped there.
145+ m = step (m , tt .up )
146+ assert .Equal (t , 2 , m .cursor )
147+
148+ // Down moves toward the bottom of the stack (lower index).
149+ m = step (m , tt .down )
150+ assert .Equal (t , 1 , m .cursor )
151+ m = step (m , tt .up )
152+ assert .Equal (t , 2 , m .cursor )
153+ })
154+ }
140155}
141156
142157func TestTruncate_WideRunes (t * testing.T ) {
@@ -260,6 +275,18 @@ func TestMethod_SelectAndAdvance(t *testing.T) {
260275 assert .Equal (t , "rebase" , m .method )
261276}
262277
278+ func TestMethod_VimNavigation (t * testing.T ) {
279+ m := New (baseOptions ())
280+ m = step (m , keyType (tea .KeyEnter ))
281+ require .Equal (t , StepMethod , m .step )
282+ require .Equal (t , 1 , m .methodCursor )
283+
284+ m = step (m , keyRune ('j' ))
285+ assert .Equal (t , 2 , m .methodCursor )
286+ m = step (m , keyRune ('k' ))
287+ assert .Equal (t , 1 , m .methodCursor )
288+ }
289+
263290func TestMethod_EscCancels (t * testing.T ) {
264291 m := New (baseOptions ())
265292 m = step (m , keyType (tea .KeyEnter ))
@@ -392,9 +419,12 @@ func TestView_RendersBannerAndSteps(t *testing.T) {
392419 assert .Contains (t , sel , "Confirm" )
393420 assert .Contains (t , sel , "Will merge 3 PRs into main" )
394421 assert .Contains (t , sel , "feat-a" ) // branch shown on the item's second line
422+ assert .Contains (t , sel , "↓↑/jk" )
395423
396424 m = step (m , keyType (tea .KeyTab ))
397- assert .Contains (t , m .View (), "Squash and merge" ) // method labels, no subheading
425+ method := m .View ()
426+ assert .Contains (t , method , "Squash and merge" ) // method labels, no subheading
427+ assert .Contains (t , method , "↓↑/jk" )
398428
399429 m = step (m , keyType (tea .KeyTab ))
400430 confirm := m .View ()
0 commit comments