From 29d05e23f98a5d4d429dff51a1210fbea9e018aa Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 8 Aug 2026 15:52:43 +0200 Subject: [PATCH] Add tests for the scroll-into-view regressions we fixed by hand Since scrolling the selection into view became opt-in, five places have had to be fixed by hand after the fact, none of them with a test. Cover them now: making the scrolling automatic has to keep all five working, and once it does, the hand-added scroll calls can go. Two of them assert that the selection is visible rather than on an exact scroll position, because the panel they look at changes height along the way (filtering mode switches to half screen), or because what matters is only that the commit we jumped to can be seen. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/integration/components/view_driver.go | 14 +++++ pkg/integration/tests/test_list.go | 5 ++ .../filtering_scrolls_selection_into_view.go | 62 +++++++++++++++++++ ...base_commit_for_fixup_scrolls_into_view.go | 35 +++++++++++ .../tests/ui/menu_scroll_position_is_reset.go | 39 ++++++++++++ ...move_commit_scrolls_selection_into_view.go | 31 ++++++++++ .../sub_commits_scroll_position_is_reset.go | 39 ++++++++++++ 7 files changed, 225 insertions(+) create mode 100644 pkg/integration/tests/ui/filtering_scrolls_selection_into_view.go create mode 100644 pkg/integration/tests/ui/find_base_commit_for_fixup_scrolls_into_view.go create mode 100644 pkg/integration/tests/ui/menu_scroll_position_is_reset.go create mode 100644 pkg/integration/tests/ui/move_commit_scrolls_selection_into_view.go create mode 100644 pkg/integration/tests/ui/sub_commits_scroll_position_is_reset.go diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index 9b895e462..23e3502a1 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -366,6 +366,20 @@ func (self *ViewDriver) OriginY(expected int) *ViewDriver { return self } +// asserts that the selected line is inside the visible area of the view +func (self *ViewDriver) SelectedLineIsVisible() *ViewDriver { + self.t.assertWithRetries(func() (bool, string) { + view := self.getView() + firstVisible, lastVisible := view.OriginY(), view.OriginY()+view.InnerHeight()-1 + actual := view.SelectedLineIdx() + return actual >= firstVisible && actual <= lastVisible, + fmt.Sprintf("%s: Expected the selected line (%d) to be visible, but only lines %d to %d are", + self.context, actual, firstVisible, lastVisible) + }) + + return self +} + func (self *ViewDriver) OriginYAtLeast(expected int) *ViewDriver { self.t.assertEventually(func() (bool, string) { var actual int diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index ab7bf196c..a945e324d 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -502,10 +502,14 @@ var tests = []*components.IntegrationTest{ ui.DisableSwitchTabWithPanelJumpKeys, ui.DragBeyondViewport, ui.EmptyMenu, + ui.FilteringScrollsSelectionIntoView, + ui.FindBaseCommitForFixupScrollsIntoView, ui.HideSidePanel, ui.KeybindingSuggestionsDontCrashOnDisabledBindings, ui.KeybindingSuggestionsWhenSwitchingRepos, + ui.MenuScrollPositionIsReset, ui.ModeSpecificKeybindingSuggestions, + ui.MoveCommitScrollsSelectionIntoView, ui.OpenLinkFailure, ui.PageUpAndDown, ui.PromoteTabToSidePanel, @@ -513,6 +517,7 @@ var tests = []*components.IntegrationTest{ ui.RangeSelectWithAutoscroll, ui.ReloadSidePanels, ui.ReorderSidePanels, + ui.SubCommitsScrollPositionIsReset, ui.SwitchTabFromMenu, ui.SwitchTabWithPanelJumpKeys, undo.UndoCheckoutAndDrop, diff --git a/pkg/integration/tests/ui/filtering_scrolls_selection_into_view.go b/pkg/integration/tests/ui/filtering_scrolls_selection_into_view.go new file mode 100644 index 000000000..3f1ab4d84 --- /dev/null +++ b/pkg/integration/tests/ui/filtering_scrolls_selection_into_view.go @@ -0,0 +1,62 @@ +package ui + +import ( + "fmt" + + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FilteringScrollsSelectionIntoView = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Entering and leaving filtering mode scrolls the selected commit into view", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + for i := range 40 { + file := "otherFile" + if i%2 == 0 { + file = "filterFile" + } + shell.UpdateFileAndAdd(file, fmt.Sprintf("content %02d", i)) + shell.Commit(fmt.Sprintf("commit %02d", i)) + } + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("commit 00")). + OriginYAtLeast(1). + Press(keys.Universal.FilteringMenu) + + t.ExpectPopup().Menu(). + Title(Equals("Filtering")). + Select(Contains("Enter path to filter by")). + Confirm() + t.ExpectPopup().Prompt(). + Title(Equals("Enter path:")). + Type("filterFile"). + Confirm() + + // The filtered list has nothing to do with the one that was showing, so + // its scroll position doesn't either: we start at the top again + t.Views().Commits(). + IsFocused(). + SelectedLine(Contains("commit 38")). + SelectedLineIdx(0). + OriginY(0). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("commit 00")). + PressEscape() + + // Leaving filtering mode keeps the commit selected, at its position in + // the full list, which needs scrolling to again + t.Views().Commits(). + IsFocused(). + SelectedLine(Contains("commit 00")). + SelectedLineIsVisible() + }, +}) diff --git a/pkg/integration/tests/ui/find_base_commit_for_fixup_scrolls_into_view.go b/pkg/integration/tests/ui/find_base_commit_for_fixup_scrolls_into_view.go new file mode 100644 index 000000000..b0c63dcf5 --- /dev/null +++ b/pkg/integration/tests/ui/find_base_commit_for_fixup_scrolls_into_view.go @@ -0,0 +1,35 @@ +package ui + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FindBaseCommitForFixupScrollsIntoView = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Finding the base commit for a fixup scrolls it into view", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.NewBranch("mybranch"). + EmptyCommit("1st commit"). + CreateFileAndAdd("file1", "line 1\nline 2\nline 3\n"). + Commit("base commit"). + CreateNCommits(40). + UpdateFile("file1", "line 1\nline 2 changed\nline 3\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Focus(). + Press(keys.Files.FindBaseCommitForFixup) + + // The base commit is at the very bottom of the list, far below the + // visible area + t.Views().Commits(). + IsFocused(). + SelectedLine(Contains("base commit")). + SelectedLineIsVisible() + }, +}) diff --git a/pkg/integration/tests/ui/menu_scroll_position_is_reset.go b/pkg/integration/tests/ui/menu_scroll_position_is_reset.go new file mode 100644 index 000000000..448e0b995 --- /dev/null +++ b/pkg/integration/tests/ui/menu_scroll_position_is_reset.go @@ -0,0 +1,39 @@ +package ui + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var MenuScrollPositionIsReset = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "A menu that is opened after a scrolled down one starts at the top again", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateFile("myfile", "myfile") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Press(keys.Universal.OptionMenu) + + t.Views().Menu(). + IsFocused(). + // The first line is a section header, so the first item is at index 1 + SelectedLineIdx(1). + OriginY(0). + Press(keys.Universal.GotoBottom). + OriginYAtLeast(1). + PressEscape() + + t.Views().Files(). + IsFocused(). + Press(keys.Universal.OptionMenu) + + t.Views().Menu(). + IsFocused(). + SelectedLineIdx(1). + OriginY(0) + }, +}) diff --git a/pkg/integration/tests/ui/move_commit_scrolls_selection_into_view.go b/pkg/integration/tests/ui/move_commit_scrolls_selection_into_view.go new file mode 100644 index 000000000..a665b548d --- /dev/null +++ b/pkg/integration/tests/ui/move_commit_scrolls_selection_into_view.go @@ -0,0 +1,31 @@ +package ui + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var MoveCommitScrollsSelectionIntoView = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Moving a commit down scrolls it into view if it isn't visible", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateNCommits(40) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + SelectedLine(Contains("commit-40")). + // Scroll the selected commit out of view with the mouse wheel + ScrollWheelDown(). + ScrollWheelDown(). + OriginY(4). + Press(keys.Commits.MoveDownCommit). + SelectedLine(Contains("commit-40")). + SelectedLineIdx(1). + SelectedLineIsVisible() + }, +}) diff --git a/pkg/integration/tests/ui/sub_commits_scroll_position_is_reset.go b/pkg/integration/tests/ui/sub_commits_scroll_position_is_reset.go new file mode 100644 index 000000000..1de8acb70 --- /dev/null +++ b/pkg/integration/tests/ui/sub_commits_scroll_position_is_reset.go @@ -0,0 +1,39 @@ +package ui + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var SubCommitsScrollPositionIsReset = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Viewing the commits of a branch again after scrolling down starts at the top again", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateNCommits(40) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Focus(). + PressEnter() + + t.Views().SubCommits(). + IsFocused(). + OriginY(0). + Press(keys.Universal.GotoBottom). + OriginYAtLeast(1). + PressEscape() + + t.Views().Branches(). + IsFocused(). + PressEnter() + + t.Views().SubCommits(). + IsFocused(). + SelectedLineIdx(0). + OriginY(0) + }, +})