Let focused diff tests own shared staging behavior

Keeping the same staging interactions covered through the explorer would
pin the suite to the panel that this branch removes. The focused main
view now owns line, range, hunk, navigation, search, context-size, and
rapid-input coverage.

Co-Authored-By: GitHub Copilot <copilot@github.com>
This commit is contained in:
Stefan Haller
2026-10-05 11:44:42 +02:00
co-authored by GitHub Copilot
parent fd70aee09b
commit 2be96483fa
12 changed files with 12 additions and 697 deletions
@@ -1,4 +1,4 @@
package staging
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
@@ -26,7 +26,7 @@ var StagePartialBlockOfChangesFirstLines = NewIntegrationTest(NewIntegrationTest
).
PressEnter()
t.Views().Staging().
t.Views().Main().
IsFocused().
ContainsLines(
Contains(" 1"),
@@ -53,7 +53,7 @@ var StagePartialBlockOfChangesFirstLines = NewIntegrationTest(NewIntegrationTest
SelectedLines(Contains("+3b")).
PressPrimaryAction()
t.Views().StagingSecondary().
t.Views().Secondary().
ContainsLines(
Contains(" 1"),
Contains("-2"),
@@ -1,4 +1,4 @@
package staging
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
@@ -26,7 +26,7 @@ var StagePartialBlockOfChangesLastLines = NewIntegrationTest(NewIntegrationTestA
).
PressEnter()
t.Views().Staging().
t.Views().Main().
IsFocused().
ContainsLines(
Contains(" 1"),
@@ -53,7 +53,7 @@ var StagePartialBlockOfChangesLastLines = NewIntegrationTest(NewIntegrationTestA
SelectedLines(Contains("+7b")).
PressPrimaryAction()
t.Views().StagingSecondary().
t.Views().Secondary().
ContainsLines(
Contains(" 3"),
Contains(" 4"),
@@ -1,4 +1,4 @@
package staging
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
@@ -26,7 +26,7 @@ var StagePartialBlockOfChangesMiddleLines = NewIntegrationTest(NewIntegrationTes
).
PressEnter()
t.Views().Staging().
t.Views().Main().
IsFocused().
ContainsLines(
Contains(" 1"),
@@ -53,7 +53,7 @@ var StagePartialBlockOfChangesMiddleLines = NewIntegrationTest(NewIntegrationTes
SelectedLines(Contains("+5b")).
PressPrimaryAction()
t.Views().StagingSecondary().
t.Views().Secondary().
// This is not the desired result, ideally the added lines would come right after the
// deleted lines. However, this is hard to do, and it's a lot less common than staging
// either the first lines or last lines of a block of changes, so we live with the
@@ -1,123 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var DiffContextChange = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Change the number of diff context lines while in the staging panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
// need to be working with a few lines so that git perceives it as two separate hunks
shell.CreateFileAndAdd("file1", "1a\n2a\n3a\n4a\n5a\n6a\n7a\n8a\n9a\n10a\n11a\n12a\n13a\n14a\n15a")
shell.Commit("one")
shell.UpdateFile("file1", "1a\n2a\n3b\n4a\n5a\n6a\n7a\n8a\n9a\n10a\n11a\n12a\n13b\n14a\n15a")
// hunk looks like:
// diff --git a/file1 b/file1
// index 3653080..a6388b6 100644
// --- a/file1
// +++ b/file1
// @@ -1,6 +1,6 @@
// 1a
// 2a
// -3a
// +3b
// 4a
// 5a
// 6a
// @@ -10,6 +10,6 @@
// 10a
// 11a
// 12a
// -13a
// +13b
// 14a
// 15a
// \ No newline at end of file
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.IncreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 4"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.DecreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 3"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.DecreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 2"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.DecreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 1"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
PressPrimaryAction().
Press(keys.Universal.TogglePanel)
t.Views().StagingSecondary().
IsFocused().
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.DecreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 0"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.IncreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 1"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.IncreaseContextInDiffView).
Tap(func() {
t.ExpectToast(Equals("Changed diff context size to 2"))
}).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
)
},
})
-42
View File
@@ -1,42 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var Search = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Use the search feature in the staging panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateFile("file1", "one\ntwo\nthree\nfour\nfive")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
Press(keys.Universal.StartSearch).
Tap(func() {
t.ExpectSearch().
Type("four").
Confirm()
t.Views().Search().IsVisible().Content(Contains("matches for 'four' (1 of 1)"))
}).
SelectedLine(Contains("+four")). // stage the line
PressPrimaryAction().
Content(DoesNotContain("+four")).
Tap(func() {
t.Views().StagingSecondary().
Content(Contains("+four"))
})
},
})
@@ -1,61 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
// Tests that after staging individual lines from a consecutive changes block,
// the cursor advances to the correct next change. The file has two separate
// hunks so that we can verify the cursor crosses hunk boundaries correctly.
var SelectNextLineAfterStagingInTwoHunkDiff = NewIntegrationTest(NewIntegrationTestArgs{
Description: "After staging lines from a two-hunk diff, the cursor advances correctly",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
// Use 7 context lines between the two change blocks so that git creates
// two separate hunks.
shell.CreateFileAndAdd("file1", "1\n2\na\nb\nc\nd\ne\nf\ng\n3\n4\n")
shell.Commit("one")
shell.UpdateFile("file1", "1b\n2b\na\nb\nc\nd\ne\nf\ng\n3b\n4b\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
ContainsLines(
Contains("-1"),
Contains("-2"),
Contains("+1b"),
Contains("+2b"),
Contains(" a"),
Contains(" b"),
Contains(" c"),
Contains("@@"),
Contains(" e"),
Contains(" f"),
Contains(" g"),
Contains("-3"),
Contains("-4"),
Contains("+3b"),
Contains("+4b"),
).
NavigateToLine(Contains("-2")).
PressPrimaryAction().
SelectedLine(Contains("+1b")).
PressPrimaryAction().
SelectedLine(Contains("+2b")).
PressPrimaryAction().
SelectedLine(Contains("-3"))
},
})
@@ -1,51 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
// Tests that after staging an isolated addition (one that is alone in its block of changes), the
// cursor stays at the first change of the next block of changes which moves up to the same line,
// even if that block starts with a deletion.
var SelectNextLineAfterStagingIsolatedAddedLine = NewIntegrationTest(NewIntegrationTestArgs{
Description: "After staging an isolated added line, the cursor advances to the next hunk's first change",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
shell.Commit("one")
shell.UpdateFile("file1", "1\n2\n3\nnew\n4\n5\n6\n7b\n8\n9\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
ContainsLines(
Contains(" 1"),
Contains(" 2"),
Contains(" 3"),
Contains("+new"),
Contains(" 4"),
Contains(" 5"),
Contains(" 6"),
Contains("-7"),
Contains("+7b"),
Contains(" 8"),
Contains(" 9"),
).
SelectedLine(Contains("+new")).
PressPrimaryAction().
SelectedLine(Contains("-7"))
},
})
@@ -1,120 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StageHunks = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stage and unstage various hunks of a file in the staging panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "1a\n2a\n3a\n4a\n5a\n6a\n7a\n8a")
shell.Commit("one")
shell.UpdateFile("file1", "1a\n2a\n3b\n4a\n5a\n6b\n7a\n8a")
// hunk looks like:
// diff --git a/file1 b/file1
// index 3653080..a6388b6 100644
// --- a/file1
// +++ b/file1
// @@ -1,6 +1,6 @@
// 1a
// 2a
// -3a
// +3b
// 4a
// 5a
// -6a
// +6b
// 7a
// 8a
// \ No newline at end of file
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
SelectedLines(
Contains("-3a"),
).
Press(keys.Universal.NextBlock).
SelectedLines(
Contains("-6a"),
).
Press(keys.Main.ToggleSelectHunk).
SelectedLines(
Contains("-6a"),
Contains("+6b"),
).
// when in hunk mode, pressing up/down moves us up/down by a hunk
SelectPreviousItem().
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
SelectNextItem().
SelectedLines(
Contains("-6a"),
Contains("+6b"),
).
// stage the second hunk
PressPrimaryAction().
ContainsLines(
Contains("-3a"),
Contains("+3b"),
).
Tap(func() {
t.Views().StagingSecondary().
ContainsLines(
Contains("-6a"),
Contains("+6b"),
)
}).
Press(keys.Universal.TogglePanel)
t.Views().StagingSecondary().
IsFocused().
// after toggling panel, we're back to only having selected a single line
SelectedLines(
Contains("-6a"),
).
PressPrimaryAction().
SelectedLines(
Contains("+6b"),
).
PressPrimaryAction().
IsEmpty()
t.Views().Staging().
IsFocused().
SelectedLines(
Contains("-3a"),
).
Press(keys.Main.ToggleSelectHunk).
SelectedLines(
Contains(`-3a`),
Contains(`+3b`),
).
Press(keys.Universal.Remove).
Tap(func() {
t.Common().ConfirmDiscardLines()
}).
Content(DoesNotContain("-3a").DoesNotContain("+3b")).
SelectedLines(
Contains("-6a"),
Contains("+6b"),
)
},
})
@@ -1,50 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
// The second space is pressed before the refresh triggered by the first one
// has updated the staging panel. That refresh is what moves the selection to
// the next hunk, so the second press must not be handled until it has landed;
// handling it earlier would try to stage the first hunk a second time.
var StageHunksWithRapidKeypresses = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stage two hunks with two space presses in rapid succession",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = true
},
SetupRepo: func(shell *Shell) {
// Use 7 context lines between the two change blocks so that git creates
// two separate hunks.
shell.CreateFileAndAdd("file1", "1\n2\na\nb\nc\nd\ne\nf\ng\n3\n4\n")
shell.Commit("one")
shell.UpdateFile("file1", "1b\n2b\na\nb\nc\nd\ne\nf\ng\n3b\n4b\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
PressRapidly(keys.Universal.Select, keys.Universal.Select)
t.Views().StagingSecondary().
IsFocused().
ContainsLines(
Contains("+1b"),
Contains("+2b"),
).
ContainsLines(
Contains("+3b"),
Contains("+4b"),
)
},
})
@@ -1,122 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StageLines = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stage and unstage various lines of a file in the staging panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "one\ntwo\n")
shell.Commit("one")
shell.UpdateFile("file1", "one\ntwo\nthree\nfour\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
SelectedLines(Contains("+three")).
// stage 'three'
PressPrimaryAction().
// 'three' moves over to the staging secondary panel
Content(DoesNotContain("+three")).
Tap(func() {
t.Views().StagingSecondary().
ContainsLines(
Contains("+three"),
)
}).
SelectedLines(Contains("+four")).
// stage 'four'
PressPrimaryAction().
// nothing left in our staging panel
IsEmpty()
// because we've staged everything we get moved to the staging secondary panel
// do the same thing as above, moving the lines back to the staging panel
t.Views().StagingSecondary().
IsFocused().
ContainsLines(
Contains("+three"),
Contains("+four"),
).
SelectedLines(Contains("+three")).
PressPrimaryAction().
Content(DoesNotContain("+three")).
Tap(func() {
t.Views().Staging().
ContainsLines(
Contains("+three"),
)
}).
SelectedLines(Contains("+four")).
// pressing 'remove' has the same effect as pressing space when in the staging secondary panel
Press(keys.Universal.Remove).
IsEmpty()
// stage one line and then manually toggle to the staging secondary panel
t.Views().Staging().
IsFocused().
ContainsLines(
Contains("+three"),
Contains("+four"),
).
SelectedLines(Contains("+three")).
PressPrimaryAction().
Content(DoesNotContain("+three")).
Tap(func() {
t.Views().StagingSecondary().
Content(Contains("+three"))
}).
Press(keys.Universal.TogglePanel)
// manually toggle back to the staging panel
t.Views().StagingSecondary().
IsFocused().
Press(keys.Universal.TogglePanel)
t.Views().Staging().
SelectedLines(Contains("+four")).
// discard the line
Press(keys.Universal.Remove).
Tap(func() {
t.ExpectPopup().Confirmation().
Title(Equals("Discard change")).
Content(Contains("Are you sure you want to discard this change")).
Confirm()
}).
IsEmpty()
t.Views().StagingSecondary().
IsFocused().
ContainsLines(
Contains("+three"),
).
// return to file
PressEscape()
t.Views().Files().
IsFocused().
Lines(
Contains("M file1").IsSelected(),
).
PressEnter()
// because we only have a staged change we'll land in the staging secondary panel
t.Views().StagingSecondary().
IsFocused()
},
})
@@ -1,108 +0,0 @@
package staging
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StageRanges = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stage and unstage various ranges of a file in the staging panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "one\ntwo\n")
shell.Commit("one")
shell.UpdateFile("file1", "one\ntwo\nthree\nfour\nfive\nsix\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressEnter()
t.Views().Staging().
IsFocused().
SelectedLines(
Contains("+three"),
).
Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("+five")).
SelectedLines(
Contains("+three"),
Contains("+four"),
Contains("+five"),
).
// stage the three lines we've just selected
PressPrimaryAction().
SelectedLines(
Contains("+six"),
).
ContainsLines(
Contains(" five"),
Contains("+six"),
).
Tap(func() {
t.Views().StagingSecondary().
ContainsLines(
Contains("+three"),
Contains("+four"),
Contains("+five"),
)
}).
Press(keys.Universal.TogglePanel)
t.Views().StagingSecondary().
IsFocused().
SelectedLines(
Contains("+three"),
).
Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("+five")).
SelectedLines(
Contains("+three"),
Contains("+four"),
Contains("+five"),
).
// unstage the three selected lines
PressPrimaryAction().
// nothing left in our staging secondary panel
IsEmpty().
Tap(func() {
t.Views().Staging().
ContainsLines(
Contains("+three"),
Contains("+four"),
Contains("+five"),
Contains("+six"),
)
})
t.Views().Staging().
IsFocused().
// coincidentally we land at '+four' here. Maybe we should instead land
// at '+three'? given it's at the start of the hunk?
SelectedLines(
Contains("+four"),
).
Press(keys.Universal.ToggleRangeSelect).
SelectNextItem().
SelectedLines(
Contains("+four"),
Contains("+five"),
).
Press(keys.Universal.Remove).
Tap(func() {
t.Common().ConfirmDiscardLines()
}).
ContainsLines(
Contains("+three"),
Contains("+six"),
)
},
})
+3 -11
View File
@@ -443,6 +443,9 @@ var tests = []*components.IntegrationTest{
main_view.StageDiffLines,
main_view.StageDiffLinesOfAPathWithASpace,
main_view.StageHunksWithRapidKeypresses,
main_view.StagePartialBlockOfChangesFirstLines,
main_view.StagePartialBlockOfChangesLastLines,
main_view.StagePartialBlockOfChangesMiddleLines,
main_view.StageRangeSpanningFiles,
main_view.StageUnderConformingDiffRenderer,
main_view.StageUnderUnsupportedDiffRenderer,
@@ -513,18 +516,7 @@ var tests = []*components.IntegrationTest{
shell_commands.History,
shell_commands.OmitFromHistory,
staging.DiffChangeScreenMode,
staging.DiffContextChange,
staging.DiscardAllChanges,
staging.Search,
staging.SelectNextLineAfterStagingInTwoHunkDiff,
staging.SelectNextLineAfterStagingIsolatedAddedLine,
staging.StageHunks,
staging.StageHunksWithRapidKeypresses,
staging.StageLines,
staging.StagePartialBlockOfChangesFirstLines,
staging.StagePartialBlockOfChangesLastLines,
staging.StagePartialBlockOfChangesMiddleLines,
staging.StageRanges,
stash.Apply,
stash.ApplyPatch,
stash.CreateBranch,