mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-24 02:24:25 -05:00
Add a test that a background refresh keeps the scroll position
The one behaviour that made scrolling the selection into view opt-in in the first place — a background refresh must not yank the view back to a selection the user scrolled away from — has never been covered by a test. It's about to become the one case that the automatic scrolling has to suppress, so cover it first. Getting there needs two things from the test harness: mouse wheel events, which are the only way to scroll a list panel without moving the selection, and a way to trigger a background refresh. The periodic routine that issues it is turned off in tests, and turning it on would mean waiting for its timer and hoping it fires while we're looking, so drive the refresh directly instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a881fb7ee0
commit
e9faf0325d
@@ -69,6 +69,10 @@ func (self *GuiDriver) MouseMove(x, y int) {
|
||||
self.replayMouseEvent(x, y, tcell.ButtonPrimary)
|
||||
}
|
||||
|
||||
func (self *GuiDriver) ScrollWheelDown(x, y int) {
|
||||
self.replayMouseEvent(x, y, tcell.WheelDown)
|
||||
}
|
||||
|
||||
func (self *GuiDriver) MouseRelease(x, y int) {
|
||||
self.replayMouseEvent(x, y, tcell.ButtonNone)
|
||||
}
|
||||
@@ -128,6 +132,16 @@ func (self *GuiDriver) FocusInAndClick(x, y int) {
|
||||
self.waitTillIdle()
|
||||
}
|
||||
|
||||
// RefreshInBackground performs the refresh that the background routines perform
|
||||
// on a timer (see BackgroundRoutineMgr). Tests drive it directly rather than
|
||||
// turning those routines on, so that they neither wait for a timer nor depend on
|
||||
// one firing at a particular moment.
|
||||
func (self *GuiDriver) RefreshInBackground() {
|
||||
self.gui.c.RefreshFromWorker(types.RefreshOptions{Background: true})
|
||||
|
||||
self.waitTillIdle()
|
||||
}
|
||||
|
||||
func (self *GuiDriver) PretendMergeOrRebaseStartedInLazygit() {
|
||||
self.gui.onUIThread(func() error {
|
||||
self.gui.State.SetMergeOrRebaseStartedInLazygit(true)
|
||||
|
||||
@@ -78,6 +78,12 @@ func (self *TestDriver) repeatMouseMove() {
|
||||
self.mouseMove(self.mouseX, self.mouseY)
|
||||
}
|
||||
|
||||
func (self *TestDriver) scrollWheelDown(x, y int) {
|
||||
self.SetCaption(fmt.Sprintf("Scrolling down at %d, %d", x, y))
|
||||
self.gui.ScrollWheelDown(x, y)
|
||||
self.Wait(self.inputDelay)
|
||||
}
|
||||
|
||||
func (self *TestDriver) mouseRelease() {
|
||||
self.SetCaption(fmt.Sprintf("Releasing mouse at %d, %d", self.mouseX, self.mouseY))
|
||||
self.gui.MouseRelease(self.mouseX, self.mouseY)
|
||||
@@ -136,6 +142,15 @@ func (self *TestDriver) Log(message string) {
|
||||
self.gui.LogUI(message)
|
||||
}
|
||||
|
||||
// RefreshInBackground performs the refresh that lazygit's background routines
|
||||
// perform on a timer, e.g. to pick up changes made by RunCommand. Tests use this
|
||||
// rather than turning those routines on and waiting for them.
|
||||
func (self *TestDriver) RefreshInBackground() {
|
||||
self.SetCaption("Refreshing in the background")
|
||||
self.gui.RefreshInBackground()
|
||||
self.Wait(self.inputDelay)
|
||||
}
|
||||
|
||||
// allows the user to run shell commands during the test to emulate background activity
|
||||
func (self *TestDriver) Shell() *Shell {
|
||||
return self.shell
|
||||
|
||||
@@ -56,6 +56,12 @@ func (self *fakeGuiDriver) MouseRelease(x, y int) {
|
||||
self.releasedCoordinates = append(self.releasedCoordinates, coordinate{x: x, y: y})
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) ScrollWheelDown(x, y int) {
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) RefreshInBackground() {
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) OnUIThreadAndWait(f func()) {
|
||||
f()
|
||||
}
|
||||
|
||||
@@ -544,6 +544,15 @@ func (self *ViewDriver) MouseMoveToBottom(x int) *ViewDriver {
|
||||
return self.MouseMove(x, self.getView().InnerHeight()-1)
|
||||
}
|
||||
|
||||
// scrolls the view down by one notch of the mouse wheel, i.e. by
|
||||
// gui.scrollHeight lines. This moves the scroll position without moving the
|
||||
// selection.
|
||||
func (self *ViewDriver) ScrollWheelDown() *ViewDriver {
|
||||
offsetX, offsetY, _, _ := self.getView().Dimensions()
|
||||
self.t.scrollWheelDown(offsetX+1, offsetY+1)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *ViewDriver) RepeatMouseMove() *ViewDriver {
|
||||
self.t.repeatMouseMove()
|
||||
return self
|
||||
|
||||
@@ -496,6 +496,7 @@ var tests = []*components.IntegrationTest{
|
||||
tag.Reset,
|
||||
tag.ResetToDuplicateNamedBranch,
|
||||
ui.Accordion,
|
||||
ui.BackgroundRefreshKeepsScrollPosition,
|
||||
ui.BranchesNotFirstTab,
|
||||
ui.CommitsNotFirstTab,
|
||||
ui.DisableSwitchTabWithPanelJumpKeys,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var BackgroundRefreshKeepsScrollPosition = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "A background refresh doesn't scroll the selection back into view",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
Width: 120,
|
||||
Height: 30,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.EmptyCommit("initial commit")
|
||||
for i := range 20 {
|
||||
shell.CreateFile(fmt.Sprintf("file%02d", i), "")
|
||||
}
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
SelectNextItem().
|
||||
SelectedLine(Contains("file00")).
|
||||
// Scroll the selection out of view with the mouse wheel
|
||||
ScrollWheelDown().
|
||||
ScrollWheelDown().
|
||||
OriginY(4).
|
||||
Tap(func() {
|
||||
t.Shell().CreateFile("aaa", "")
|
||||
t.RefreshInBackground()
|
||||
}).
|
||||
// The new file sorts before the selected one, so the selection has
|
||||
// moved down a line; the view must stay where the user left it though
|
||||
SelectedLineIdx(2).
|
||||
OriginY(4)
|
||||
},
|
||||
})
|
||||
@@ -31,6 +31,9 @@ type GuiDriver interface {
|
||||
ClickAndHold(int, int)
|
||||
MouseMove(int, int)
|
||||
MouseRelease(int, int)
|
||||
ScrollWheelDown(int, int)
|
||||
// Perform the refresh that a background routine would perform on a timer
|
||||
RefreshInBackground()
|
||||
// Can be used to avoid data races with the UI thread in the uncommon cases that
|
||||
// the test driver needs to assert state while the gui is not idle.
|
||||
OnUIThreadAndWait(func())
|
||||
|
||||
Reference in New Issue
Block a user