Add test helpers for a menu's filter row

Its footer, the hint in the menu's subtitle, where the row sits in
relation to the menu and the tooltip, and whether the text cursor is
showing are all things the tests for it need to look at.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller 2026-08-25 09:36:03 +02:00
parent 2048c7f0a6
commit 68355862c1
6 changed files with 83 additions and 0 deletions

View file

@ -181,6 +181,10 @@ func (self *GuiDriver) CurrentContext() types.Context {
return self.gui.State.ContextMgr.Current()
}
func (self *GuiDriver) CursorVisible() bool {
return self.gui.g.Cursor
}
func (self *GuiDriver) ContextForView(viewName string) types.Context {
context, ok := self.gui.helpers.View.ContextForView(viewName)
if !ok {

View file

@ -97,6 +97,24 @@ func (self *TestDriver) GlobalPress(key config.Keybinding) {
self.press(key[0])
}
// asserts that the terminal's text cursor is shown, i.e. that there is a text
// field to type into
func (self *TestDriver) CursorIsVisible() *TestDriver {
self.assertWithRetries(func() (bool, string) {
return self.gui.CursorVisible(), "Expected the cursor to be visible"
})
return self
}
func (self *TestDriver) CursorIsHidden() *TestDriver {
self.assertWithRetries(func() (bool, string) {
return !self.gui.CursorVisible(), "Expected the cursor to be hidden"
})
return self
}
// FocusIn simulates the terminal window regaining focus, which causes lazygit
// to reload any config files that changed while it was in the background.
func (self *TestDriver) FocusIn() {

View file

@ -88,6 +88,10 @@ func (self *fakeGuiDriver) CurrentContext() types.Context {
return nil
}
func (self *fakeGuiDriver) CursorVisible() bool {
return false
}
func (self *fakeGuiDriver) ContextForView(viewName string) types.Context {
return nil
}

View file

@ -41,6 +41,53 @@ func (self *ViewDriver) Title(expected *TextMatcher) *ViewDriver {
return self
}
// asserts that the view has the expected footer, i.e. the "x of y" text on its
// bottom border
func (self *ViewDriver) Footer(expected *TextMatcher) *ViewDriver {
self.t.assertWithRetries(func() (bool, string) {
actual := self.getView().Footer
return expected.context(fmt.Sprintf("%s footer", self.context)).test(actual)
})
return self
}
// asserts that the view has the expected subtitle
func (self *ViewDriver) Subtitle(expected *TextMatcher) *ViewDriver {
self.t.assertWithRetries(func() (bool, string) {
actual := self.getView().Subtitle
return expected.context(fmt.Sprintf("%s subtitle", self.context)).test(actual)
})
return self
}
// asserts that the view hangs off the bottom of the given one, sharing a border
// with it
func (self *ViewDriver) SharesTopBorderWithBottomOf(upper *ViewDriver) *ViewDriver {
self.t.assertWithRetries(func() (bool, string) {
_, _, _, upperY1 := upper.getView().Dimensions()
_, y0, _, _ := self.getView().Dimensions()
return y0 == upperY1, fmt.Sprintf(
"%s: Expected view to start on row %d, where the view above it ends, but it starts on row %d",
self.context, upperY1, y0)
})
return self
}
// asserts that the view starts on the row below the given one
func (self *ViewDriver) IsImmediatelyBelow(upper *ViewDriver) *ViewDriver {
self.t.assertWithRetries(func() (bool, string) {
_, _, _, upperY1 := upper.getView().Dimensions()
_, y0, _, _ := self.getView().Dimensions()
return y0 == upperY1+1, fmt.Sprintf(
"%s: Expected view to start on row %d, but it starts on row %d", self.context, upperY1+1, y0)
})
return self
}
func (self *ViewDriver) Clear() *ViewDriver {
// clearing multiple times in case there's multiple lines
// (the clear button only clears a single line at a time)

View file

@ -124,6 +124,14 @@ func (self *Views) Menu() *ViewDriver {
return self.regularView("menu")
}
func (self *Views) MenuFilter() *ViewDriver {
return self.regularView("menuFilter")
}
func (self *Views) MenuFilterFrame() *ViewDriver {
return self.regularView("menuFilterFrame")
}
func (self *Views) Confirmation() *ViewDriver {
return self.regularView("confirmation")
}

View file

@ -45,6 +45,8 @@ type GuiDriver interface {
FocusInAndClick(int, int)
Keys() config.KeybindingConfig
CurrentContext() types.Context
// Whether the terminal's text cursor is currently shown
CursorVisible() bool
ContextForView(viewName string) types.Context
Fail(message string)
// These two log methods are for the sake of debugging while testing. There's no need to actually