From 9e76ed7c03b1a26db57bed70a299b0bdc8ee86bc Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 14 Oct 2026 14:12:19 +0200 Subject: [PATCH] Send the two clicks of a double click in tests without waiting between The test enter_and_double_click_focus_file_diff fails occasionally on CI. After it double-clicks a file, the files panel still has the focus instead of the main view. The test double-clicks by calling Click twice. Click waits for lazygit to become idle after the press and again after the release, and the first wait includes the git diff that the click starts for the main view. gocui only counts the second click as a double click if it handles it within 500ms of the first one. On a busy CI runner, where many integration tests run in parallel, the waits can take longer than that, and the second click counts as a single click. Add DoubleClick to the test driver. It replays both clicks without waiting in between, as a terminal reports a double click, and waits for lazygit to become idle only after the second one. Co-Authored-By: Claude Opus 5.5 (1M context) --- pkg/gui/gui_driver.go | 10 ++++++++++ pkg/integration/components/test_driver.go | 6 ++++++ pkg/integration/components/test_test.go | 9 +++++++-- pkg/integration/components/view_driver.go | 8 ++++++++ .../enter_and_double_click_focus_file_diff.go | 6 ++---- pkg/integration/types/types.go | 4 ++++ 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pkg/gui/gui_driver.go b/pkg/gui/gui_driver.go index 5db3d9d92..badc36283 100644 --- a/pkg/gui/gui_driver.go +++ b/pkg/gui/gui_driver.go @@ -63,6 +63,16 @@ func (self *GuiDriver) ClickWithModifier(x, y int, modifier gocui.Modifier) { self.replayMouseEvent(x, y, tcell.ButtonNone, modifier) } +func (self *GuiDriver) DoubleClick(x, y int) { + self.CheckAllToastsAcknowledged() + + for range 2 { + self.replayMouseEventWithoutWaiting(x, y, tcell.ButtonPrimary, gocui.ModNone) + self.replayMouseEventWithoutWaiting(x, y, tcell.ButtonNone, gocui.ModNone) + } + self.waitTillIdle() +} + func (self *GuiDriver) ClickAndHold(x, y int) { self.CheckAllToastsAcknowledged() self.replayMouseEvent(x, y, tcell.ButtonPrimary, gocui.ModNone) diff --git a/pkg/integration/components/test_driver.go b/pkg/integration/components/test_driver.go index 825ce5688..e924a956e 100644 --- a/pkg/integration/components/test_driver.go +++ b/pkg/integration/components/test_driver.go @@ -61,6 +61,12 @@ func (self *TestDriver) click(x, y int) { self.Wait(self.inputDelay) } +func (self *TestDriver) doubleClick(x, y int) { + self.SetCaption(fmt.Sprintf("Double-clicking %d, %d", x, y)) + self.gui.DoubleClick(x, y) + self.Wait(self.inputDelay) +} + func (self *TestDriver) clickWithModifier(x, y int, modifier gocui.Modifier, what string) { self.SetCaption(fmt.Sprintf("%s-clicking %d, %d", what, x, y)) self.gui.ClickWithModifier(x, y, modifier) diff --git a/pkg/integration/components/test_test.go b/pkg/integration/components/test_test.go index ef77ddaec..7a69c07ad 100644 --- a/pkg/integration/components/test_test.go +++ b/pkg/integration/components/test_test.go @@ -51,6 +51,10 @@ func (self *fakeGuiDriver) ClickWithModifier(x, y int, modifier gocui.Modifier) self.clickedCoordinates = append(self.clickedCoordinates, coordinate{x: x, y: y}) } +func (self *fakeGuiDriver) DoubleClick(x, y int) { + self.clickedCoordinates = append(self.clickedCoordinates, coordinate{x: x, y: y}) +} + func (self *fakeGuiDriver) ClickAndHold(x, y int) { self.heldCoordinates = append(self.heldCoordinates, coordinate{x: x, y: y}) } @@ -207,6 +211,7 @@ func TestViewDriverPointerCoordinates(t *testing.T) { AltClick(2, 3). ShiftClick(4, 5). FocusInAndClick(3, 4). + DoubleClick(6, 7). ClickAndHold(5, 6). MouseMove(7, 8). MouseMoveToBottom(9). @@ -214,12 +219,12 @@ func TestViewDriverPointerCoordinates(t *testing.T) { ScrollWheelDown() assert.Equal(t, - []coordinate{{12, 23}, {13, 24}, {15, 26}, {14, 25}}, + []coordinate{{12, 23}, {13, 24}, {15, 26}, {14, 25}, {17, 28}}, guiDriver.clickedCoordinates) assert.Equal(t, []coordinate{{16, 27}}, guiDriver.heldCoordinates) assert.Equal(t, []coordinate{{18, 29}, {20, 30}, {51, 62}}, guiDriver.movedCoordinates) assert.Equal(t, []coordinate{{11, 21}}, guiDriver.scrolledCoordinates) - assert.Equal(t, 9, guiDriver.onUIThreadCallCount) + assert.Equal(t, 10, guiDriver.onUIThreadCallCount) } func TestFailingFixture(t *testing.T) { diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index d1b65a0d9..6fae04a86 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -735,6 +735,14 @@ func (self *ViewDriver) Click(x, y int) *ViewDriver { return self } +func (self *ViewDriver) DoubleClick(x, y int) *ViewDriver { + offsetX, offsetY, _ := self.viewGeometry() + + self.t.doubleClick(offsetX+1+x, offsetY+1+y) + + return self +} + // AltClick and ShiftClick click with a modifier held down. Both modifiers are // bound to the same gestures, because no single one of them reaches lazygit in // every terminal. diff --git a/pkg/integration/tests/main_view/enter_and_double_click_focus_file_diff.go b/pkg/integration/tests/main_view/enter_and_double_click_focus_file_diff.go index a9be802b9..cfcebfa57 100644 --- a/pkg/integration/tests/main_view/enter_and_double_click_focus_file_diff.go +++ b/pkg/integration/tests/main_view/enter_and_double_click_focus_file_diff.go @@ -32,8 +32,7 @@ var EnterAndDoubleClickFocusFileDiff = NewIntegrationTest(NewIntegrationTestArgs t.Views().Files(). IsFocused(). - Click(3, 0). - Click(3, 0) + DoubleClick(3, 0) t.Views().Main(). IsFocused(). SelectedLines(Contains("-base")). @@ -60,8 +59,7 @@ var EnterAndDoubleClickFocusFileDiff = NewIntegrationTest(NewIntegrationTestArgs t.Views().CommitFiles(). IsFocused(). - Click(3, 0). - Click(3, 0) + DoubleClick(3, 0) t.Views().Main(). IsFocused(). SelectedLines(Contains("+base")) diff --git a/pkg/integration/types/types.go b/pkg/integration/types/types.go index b6655aebc..1d24fd6ad 100644 --- a/pkg/integration/types/types.go +++ b/pkg/integration/types/types.go @@ -31,6 +31,10 @@ type GuiDriver interface { // Click with a keyboard modifier held down, for the gestures that only exist // as a modified click. ClickWithModifier(int, int, gocui.Modifier) + // Two clicks in immediate succession, waiting for lazygit to become idle only + // after the second one. If it waited after the first one too, the second click + // could come too late to count as a double click. + DoubleClick(int, int) ClickAndHold(int, int) MouseMove(int, int) MouseRelease(int, int)