diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2023-07-03 12:57:11 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-03 12:57:11 +1000 |
commit | 1a36cb9f3fbcf07353b8ae73e8b055d2e0e1d794 (patch) | |
tree | f486f588c72676322c341cb9aae209a02cbf9c61 /pkg/integration | |
parent | 2be4359e87bee6c737e19b02e4c7896fbc2ebf91 (diff) | |
parent | 5d982e1d70aa9a07645a5665130f2e499b7b56c8 (diff) |
View filtering (#2680)
Diffstat (limited to 'pkg/integration')
-rw-r--r-- | pkg/integration/components/int_matcher.go | 12 | ||||
-rw-r--r-- | pkg/integration/components/menu_driver.go | 12 | ||||
-rw-r--r-- | pkg/integration/components/view_driver.go | 55 | ||||
-rw-r--r-- | pkg/integration/tests/commit/search.go | 1 | ||||
-rw-r--r-- | pkg/integration/tests/file/discard_all_dir_changes.go | 117 | ||||
-rw-r--r-- | pkg/integration/tests/file/discard_unstaged_dir_changes.go | 56 | ||||
-rw-r--r-- | pkg/integration/tests/file/discard_unstaged_file_changes.go | 41 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_commit_files.go | 84 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_files.go | 76 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_menu.go | 48 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_remote_branches.go | 59 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/nested_filter.go | 151 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/nested_filter_transient.go | 106 | ||||
-rw-r--r-- | pkg/integration/tests/test_list.go | 10 |
14 files changed, 808 insertions, 20 deletions
diff --git a/pkg/integration/components/int_matcher.go b/pkg/integration/components/int_matcher.go index c80a60c85..4cfd0f958 100644 --- a/pkg/integration/components/int_matcher.go +++ b/pkg/integration/components/int_matcher.go @@ -10,9 +10,9 @@ type IntMatcher struct { func (self *IntMatcher) EqualsInt(target int) *IntMatcher { self.appendRule(matcherRule[int]{ - name: fmt.Sprintf("equals '%d'", target), + name: fmt.Sprintf("equals %d", target), testFn: func(value int) (bool, string) { - return value == target, fmt.Sprintf("Expected '%d' to equal '%d'", value, target) + return value == target, fmt.Sprintf("Expected %d to equal %d", value, target) }, }) @@ -21,9 +21,9 @@ func (self *IntMatcher) EqualsInt(target int) *IntMatcher { func (self *IntMatcher) GreaterThan(target int) *IntMatcher { self.appendRule(matcherRule[int]{ - name: fmt.Sprintf("greater than '%d'", target), + name: fmt.Sprintf("greater than %d", target), testFn: func(value int) (bool, string) { - return value > target, fmt.Sprintf("Expected '%d' to greater than '%d'", value, target) + return value > target, fmt.Sprintf("Expected %d to greater than %d", value, target) }, }) @@ -32,9 +32,9 @@ func (self *IntMatcher) GreaterThan(target int) *IntMatcher { func (self *IntMatcher) LessThan(target int) *IntMatcher { self.appendRule(matcherRule[int]{ - name: fmt.Sprintf("less than '%d'", target), + name: fmt.Sprintf("less than %d", target), testFn: func(value int) (bool, string) { - return value < target, fmt.Sprintf("Expected '%d' to less than '%d'", value, target) + return value < target, fmt.Sprintf("Expected %d to less than %d", value, target) }, }) diff --git a/pkg/integration/components/menu_driver.go b/pkg/integration/components/menu_driver.go index ac620f5a4..4e0b0f6da 100644 --- a/pkg/integration/components/menu_driver.go +++ b/pkg/integration/components/menu_driver.go @@ -48,6 +48,18 @@ func (self *MenuDriver) TopLines(matchers ...*TextMatcher) *MenuDriver { return self } +func (self *MenuDriver) Filter(text string) *MenuDriver { + self.getViewDriver().FilterOrSearch(text) + + return self +} + +func (self *MenuDriver) LineCount(matcher *IntMatcher) *MenuDriver { + self.getViewDriver().LineCount(matcher) + + return self +} + func (self *MenuDriver) checkNecessaryChecksCompleted() { if !self.hasCheckedTitle { self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().") diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index db7e76134..2c4a23572 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -66,7 +66,7 @@ func (self *ViewDriver) Title(expected *TextMatcher) *ViewDriver { // If you only care about a subset of lines, use the ContainsLines method instead. func (self *ViewDriver) Lines(matchers ...*TextMatcher) *ViewDriver { self.validateMatchersPassed(matchers) - self.LineCount(len(matchers)) + self.LineCount(EqualsInt(len(matchers))) return self.assertLines(0, matchers...) } @@ -470,29 +470,56 @@ func (self *ViewDriver) IsEmpty() *ViewDriver { return self } -func (self *ViewDriver) LineCount(expectedCount int) *ViewDriver { - if expectedCount == 0 { - return self.IsEmpty() +func (self *ViewDriver) LineCount(matcher *IntMatcher) *ViewDriver { + view := self.getView() + + self.t.assertWithRetries(func() (bool, string) { + lineCount := self.getLineCount() + ok, _ := matcher.test(lineCount) + return ok, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %s, got %d", view.Name(), matcher.name(), lineCount) + }) + + return self +} + +func (self *ViewDriver) getLineCount() int { + // can't rely entirely on view.BufferLines because it returns 1 even if there's nothing in the view + if strings.TrimSpace(self.getView().Buffer()) == "" { + return 0 } view := self.getView() + return len(view.BufferLines()) +} +func (self *ViewDriver) IsVisible() *ViewDriver { self.t.assertWithRetries(func() (bool, string) { - lines := view.BufferLines() - return len(lines) == expectedCount, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %d, got %d", view.Name(), expectedCount, len(lines)) + return self.getView().Visible, fmt.Sprintf("%s: Expected view to be visible, but it was not", self.context) }) + return self +} + +func (self *ViewDriver) IsInvisible() *ViewDriver { self.t.assertWithRetries(func() (bool, string) { - lines := view.BufferLines() + return !self.getView().Visible, fmt.Sprintf("%s: Expected view to be visible, but it was not", self.context) + }) - // if the view has a single blank line (often the case) we want to treat that as having no lines - if len(lines) == 1 && expectedCount == 1 { - actual := strings.TrimSpace(view.Buffer()) - return actual != "", fmt.Sprintf("unexpected number of lines in view '%s'. Expected 1, got 0", view.Name()) - } + return self +} - return len(lines) == expectedCount, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %d, got %d", view.Name(), expectedCount, len(lines)) - }) +// will filter or search depending on whether the view supports filtering/searching +func (self *ViewDriver) FilterOrSearch(text string) *ViewDriver { + self.IsFocused() + + self.Press(self.t.keys.Universal.StartSearch). + Tap(func() { + self.t.ExpectSearch(). + Type(text). + Confirm() + + self.t.Views().Search().IsVisible().Content(Contains(fmt.Sprintf("matches for '%s'", text))) + }) return self } diff --git a/pkg/integration/tests/commit/search.go b/pkg/integration/tests/commit/search.go index 1d9390dc7..c0a9dfd0b 100644 --- a/pkg/integration/tests/commit/search.go +++ b/pkg/integration/tests/commit/search.go @@ -42,6 +42,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Press(keys.Universal.StartSearch). Tap(func() { t.ExpectSearch(). + Clear(). Type("o"). Confirm() diff --git a/pkg/integration/tests/file/discard_all_dir_changes.go b/pkg/integration/tests/file/discard_all_dir_changes.go new file mode 100644 index 000000000..1032a180a --- /dev/null +++ b/pkg/integration/tests/file/discard_all_dir_changes.go @@ -0,0 +1,117 @@ +package file + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var DiscardAllDirChanges = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Discarding all changes in a directory", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + }, + SetupRepo: func(shell *Shell) { + // typically we would use more bespoke shell methods here, but I struggled to find a way to do that, + // and this is copied over from a legacy integration test which did everything in a big shell script + // so I'm just copying it across. + + shell.CreateDir("dir") + + // common stuff + shell.RunShellCommand(`echo test > dir/both-deleted.txt`) + shell.RunShellCommand(`git checkout -b conflict && git add dir/both-deleted.txt`) + shell.RunShellCommand(`echo bothmodded > dir/both-modded.txt && git add dir/both-modded.txt`) + shell.RunShellCommand(`echo haha > dir/deleted-them.txt && git add dir/deleted-them.txt`) + shell.RunShellCommand(`echo haha2 > dir/deleted-us.txt && git add dir/deleted-us.txt`) + shell.RunShellCommand(`echo mod > dir/modded.txt && git add dir/modded.txt`) + shell.RunShellCommand(`echo mod > dir/modded-staged.txt && git add dir/modded-staged.txt`) + shell.RunShellCommand(`echo del > dir/deleted.txt && git add dir/deleted.txt`) + shell.RunShellCommand(`echo del > dir/deleted-staged.txt && git add dir/deleted-staged.txt`) + shell.RunShellCommand(`echo change-delete > dir/change-delete.txt && git add dir/change-delete.txt`) + shell.RunShellCommand(`echo delete-change > dir/delete-change.txt && git add dir/delete-change.txt`) + shell.RunShellCommand(`echo double-modded > dir/double-modded.txt && git add dir/double-modded.txt`) + shell.RunShellCommand(`echo "renamed\nhaha" > dir/renamed.txt && git add dir/renamed.txt`) + shell.RunShellCommand(`git commit -m one`) + + // stuff on other branch + shell.RunShellCommand(`git branch conflict_second && git mv dir/both-deleted.txt dir/added-them-changed-us.txt`) + shell.RunShellCommand(`git commit -m "dir/both-deleted.txt renamed in dir/added-them-changed-us.txt"`) + shell.RunShellCommand(`echo blah > dir/both-added.txt && git add dir/both-added.txt`) + shell.RunShellCommand(`echo mod1 > dir/both-modded.txt && git add dir/both-modded.txt`) + shell.RunShellCommand(`rm dir/deleted-them.txt && git add dir/deleted-them.txt`) + shell.RunShellCommand(`echo modded > dir/deleted-us.txt && git add dir/deleted-us.txt`) + shell.RunShellCommand(`git commit -m "two"`) + + // stuff on our branch + shell.RunShellCommand(`git checkout conflict_second`) + shell.RunShellCommand(`git mv dir/both-deleted.txt dir/changed-them-added-us.txt`) + shell.RunShellCommand(`git commit -m "both-deleted.txt renamed in dir/changed-them-added-us.txt"`) + shell.RunShellCommand(`echo mod2 > dir/both-modded.txt && git add dir/both-modded.txt`) + shell.RunShellCommand(`echo blah2 > dir/both-added.txt && git add dir/both-added.txt`) + shell.RunShellCommand(`echo modded > dir/deleted-them.txt && git add dir/deleted-them.txt`) + shell.RunShellCommand(`rm dir/deleted-us.txt && git add dir/deleted-us.txt`) + shell.RunShellCommand(`git commit -m "three"`) + shell.RunShellCommand(`git reset --hard conflict_second`) + shell.RunCommandExpectError([]string{"git", "merge", "conflict"}) + + shell.RunShellCommand(`echo "new" > dir/new.txt`) + shell.RunShellCommand(`echo "new staged" > dir/new-staged.txt && git add dir/new-staged.txt`) + shell.RunShellCommand(`echo mod2 > dir/modded.txt`) + shell.RunShellCommand(`echo mod2 > dir/modded-staged.txt && git add dir/modded-staged.txt`) + shell.RunShellCommand(`rm dir/deleted.txt`) + shell.RunShellCommand(`rm dir/deleted-staged.txt && git add dir/deleted-staged.txt`) + shell.RunShellCommand(`echo change-delete2 > dir/change-delete.txt && git add dir/change-delete.txt`) + shell.RunShellCommand(`rm dir/change-delete.txt`) + shell.RunShellCommand(`rm dir/delete-change.txt && git add dir/delete-change.txt`) + shell.RunShellCommand(`echo "changed" > dir/delete-change.txt`) + shell.RunShellCommand(`echo "change1" > dir/double-modded.txt && git add dir/double-modded.txt`) + shell.RunShellCommand(`echo "change2" > dir/double-modded.txt`) + shell.RunShellCommand(`echo before > dir/added-changed.txt && git add dir/added-changed.txt`) + shell.RunShellCommand(`echo after > dir/added-changed.txt`) + shell.RunShellCommand(`rm dir/renamed.txt && git add dir/renamed.txt`) + shell.RunShellCommand(`echo "renamed\nhaha" > dir/renamed2.txt && git add dir/renamed2.txt`) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("dir").IsSelected(), + Contains("UA").Contains("added-them-changed-us.txt"), + Contains("AA").Contains("both-added.txt"), + Contains("DD").Contains("both-deleted.txt"), + Contains("UU").Contains("both-modded.txt"), + Contains("AU").Contains("changed-them-added-us.txt"), + Contains("UD").Contains("deleted-them.txt"), + Contains("DU").Contains("deleted-us.txt"), + ). + Press(keys.Universal.Remove). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("dir")). + Select(Contains("Discard all changes")). + Confirm() + }). + Tap(func() { + t.Common().ContinueOnConflictsResolved() + }). + Lines( + Contains("dir").IsSelected(), + Contains(" M").Contains("added-changed.txt"), + Contains(" D").Contains("change-delete.txt"), + Contains("??").Contains("delete-change.txt"), + Contains(" D").Contains("deleted.txt"), + Contains(" M").Contains("double-modded.txt"), + Contains(" M").Contains("modded.txt"), + Contains("??").Contains("new.txt"), + ). + Press(keys.Universal.Remove). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("dir")). + Select(Contains("Discard all changes")). + Confirm() + }). + IsEmpty() + }, +}) diff --git a/pkg/integration/tests/file/discard_unstaged_dir_changes.go b/pkg/integration/tests/file/discard_unstaged_dir_changes.go new file mode 100644 index 000000000..89e53cab5 --- /dev/null +++ b/pkg/integration/tests/file/discard_unstaged_dir_changes.go @@ -0,0 +1,56 @@ +package file + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var DiscardUnstagedDirChanges = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Discarding unstaged changes in a directory", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + }, + SetupRepo: func(shell *Shell) { + shell.CreateDir("dir") + shell.CreateFileAndAdd("dir/file-one", "original content\n") + + shell.Commit("first commit") + + shell.UpdateFileAndAdd("dir/file-one", "original content\nnew content\n") + shell.UpdateFile("dir/file-one", "original content\nnew content\neven newer content\n") + + shell.CreateDir("dir/subdir") + shell.CreateFile("dir/subdir/unstaged-file-one", "unstaged file") + shell.CreateFile("dir/unstaged-file-two", "unstaged file") + + shell.CreateFile("unstaged-file-three", "unstaged file") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("dir").IsSelected(), + Contains("subdir"), + Contains("??").Contains("unstaged-file-one"), + Contains("MM").Contains("file-one"), + Contains("??").Contains("unstaged-file-two"), + Contains("??").Contains("unstaged-file-three"), + ). + Press(keys.Universal.Remove). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("dir")). + Select(Contains("Discard unstaged changes")). + Confirm() + }). + Lines( + Contains("dir").IsSelected(), + Contains("M ").Contains("file-one"), + // this guy remains untouched because it wasn't inside the 'dir' directory + Contains("??").Contains("unstaged-file-three"), + ) + + t.FileSystem().FileContent("dir/file-one", Equals("original content\nnew content\n")) + }, +}) diff --git a/pkg/integration/tests/file/discard_unstaged_file_changes.go b/pkg/integration/tests/file/discard_unstaged_file_changes.go new file mode 100644 index 000000000..caa5ef4ab --- /dev/null +++ b/pkg/integration/tests/file/discard_unstaged_file_changes.go @@ -0,0 +1,41 @@ +package file + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var DiscardUnstagedFileChanges = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Discarding unstaged changes in a file", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file-one", "original content\n") + + shell.Commit("first commit") + + shell.UpdateFileAndAdd("file-one", "original content\nnew content\n") + shell.UpdateFile("file-one", "original content\nnew content\neven newer content\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("MM").Contains("file-one").IsSelected(), + ). + Press(keys.Universal.Remove). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("file-one")). + Select(Contains("Discard unstaged changes")). + Confirm() + }). + Lines( + Contains("M ").Contains("file-one").IsSelected(), + ) + + t.FileSystem().FileContent("file-one", Equals("original content\nnew content\n")) + }, +}) diff --git a/pkg/integration/tests/filter_and_search/filter_commit_files.go b/pkg/integration/tests/filter_and_search/filter_commit_files.go new file mode 100644 index 000000000..953eaf34d --- /dev/null +++ b/pkg/integration/tests/filter_and_search/filter_commit_files.go @@ -0,0 +1,84 @@ +package filter_and_search + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FilterCommitFiles = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Basic commit file filtering by text", + ExtraCmdArgs: []string{}, + Skip: true, // skipping until we have implemented file view filtering + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateDir("folder1") + shell.CreateFileAndAdd("folder1/apple-grape", "apple-grape") + shell.CreateFileAndAdd("folder1/apple-orange", "apple-orange") + shell.CreateFileAndAdd("folder1/grape-orange", "grape-orange") + shell.Commit("first commit") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains(`first commit`).IsSelected(), + ). + Press(keys.Universal.Confirm) + + t.Views().CommitFiles(). + IsFocused(). + Lines( + Contains(`folder1`).IsSelected(), + Contains(`apple-grape`), + Contains(`apple-orange`), + Contains(`grape-orange`), + ). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + Contains(`folder1/grape-orange`), + ). + FilterOrSearch("apple"). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + ). + Press(keys.Files.ToggleTreeView). + // filter still applies when we toggle tree view + Lines( + Contains(`folder1`), + Contains(`apple-grape`).IsSelected(), + Contains(`apple-orange`), + ). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + ). + NavigateToLine(Contains(`folder1/apple-orange`)). + Press(keys.Universal.Return). + Lines( + Contains(`folder1/apple-grape`), + // selection is retained after escaping filter mode + Contains(`folder1/apple-orange`).IsSelected(), + Contains(`folder1/grape-orange`), + ). + Tap(func() { + t.Views().Search().IsInvisible() + }). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1`), + Contains(`apple-grape`), + Contains(`apple-orange`).IsSelected(), + Contains(`grape-orange`), + ). + FilterOrSearch("folder1/grape"). + Lines( + // first item is always selected after filtering + Contains(`folder1`).IsSelected(), + Contains(`grape-orange`), + ) + }, +}) diff --git a/pkg/integration/tests/filter_and_search/filter_files.go b/pkg/integration/tests/filter_and_search/filter_files.go new file mode 100644 index 000000000..6eae90c18 --- /dev/null +++ b/pkg/integration/tests/filter_and_search/filter_files.go @@ -0,0 +1,76 @@ +package filter_and_search + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FilterFiles = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Basic file filtering by text", + ExtraCmdArgs: []string{}, + Skip: true, // Skipping until we have implemented file view filtering + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateDir("folder1") + shell.CreateFile("folder1/apple-grape", "apple-grape") + shell.CreateFile("folder1/apple-orange", "apple-orange") + shell.CreateFile("folder1/grape-orange", "grape-orange") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Focus(). + Lines( + Contains(`folder1`).IsSelected(), + Contains(`apple-grape`), + Contains(`apple-orange`), + Contains(`grape-orange`), + ). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + Contains(`folder1/grape-orange`), + ). + FilterOrSearch("apple"). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + ). + Press(keys.Files.ToggleTreeView). + // filter still applies when we toggle tree view + Lines( + Contains(`folder1`), + Contains(`apple-grape`).IsSelected(), + Contains(`apple-orange`), + ). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1/apple-grape`).IsSelected(), + Contains(`folder1/apple-orange`), + ). + NavigateToLine(Contains(`folder1/apple-orange`)). + Press(keys.Universal.Return). + Lines( + Contains(`folder1/apple-grape`), + // selection is retained after escaping filter mode + Contains(`folder1/apple-orange`).IsSelected(), + Contains(`folder1/grape-orange`), + ). + Tap(func() { + t.Views().Search().IsInvisible() + }). + Press(keys.Files.ToggleTreeView). + Lines( + Contains(`folder1`), + Contains(`apple-grape`), + Contains(`apple-orange`).IsSelected(), + Contains(`grape-orange`), + ). + FilterOrSearch("folder1/grape"). + Lines( + // first item is always selected after filtering + Contains(`folder1`).IsSelected(), + Contains(`grape-orange`), + ) + }, +}) diff --git a/pkg/integration/tests/filter_and_search/filter_menu.go b/pkg/integration/tests/filter_and_search/filter_menu.go new file mode 100644 index 000000000..5dc15b663 --- /dev/null +++ b/pkg/integration/tests/filter_and_search/filter_menu.go @@ -0,0 +1,48 @@ +package filter_and_search + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FilterMenu = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Filtering the keybindings menu", + 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(). + Lines( + Contains(`??`).Contains(`myfile`).IsSelected(), + ). + Press(keys.Universal.OptionMenu). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("Keybindings")). + Filter("Toggle staged"). + Lines( + // menu has filtered down to the one item that matches the filter + Contains(`Toggle staged`).IsSelected(), + ). + Confirm() + }) + + t.Views().Files(). + IsFocused(). + Lines( + // file has been staged + Contains(`A `).Contains(`myfile`).IsSelected(), + ). + // Upon opening the menu again, the filter should have been reset + Press(keys.Universal.OptionMenu). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("Keybindings")). + LineCount(GreaterThan(1)) + }) + }, +}) diff --git a/pkg/integration/tests/filter_and_search/filter_remote_branches.go b/pkg/integration/tests/filter_and_search/filter_remote_branches.go new file mode 100644 index 000000000..11cfea30b --- /dev/null +++ b/pkg/integration/tests/filter_and_search/filter_remote_branches.go @@ -0,0 +1,59 @@ +package filter_and_search + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FilterRemoteBranches = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Filtering remote branches", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.NewBranch("branch-apple") + shell.EmptyCommit("commit-one") + shell.NewBranch("branch-grape") + shell.NewBranch("branch-orange") + + shell.CloneIntoRemote("origin") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Remotes(). + Focus(). + Lines( + Contains(`origin`).IsSelected(), + ). + PressEnter() + + t.Views().RemoteBranches(). + IsFocused(). + Lines( + Contains(`branch-apple`).IsSelected(), + Contains(`branch-grape`), + Contains(`branch-orange`), + ). + FilterOrSearch("grape"). + Lines( + Contains(`branch-grape`).IsSelected(), + ). + // cancel the filter + PressEscape(). + Tap(func() { + t.Views().Search().IsInvisible() + }). + Lines( + Contains(`branch-apple`), + Contains(`branch-grape`).IsSelected(), + Contains(`branch-orange`), + ). + // return to remotes view + PressEscape() + + t.Views().Remotes(). + IsFocused(). + Lines( + Contains(`origin`).IsSelected(), + ) + }, +}) diff --git a/pkg/integration/tests/filter_and_search/nested_filter.go b/pkg/integration/tests/filter_and_search/nested_filter.go new file mode 100644 index 000000000..6444ad523 --- /dev/null +++ b/pkg/integration/tests/filter_and_search/nested_filter.go @@ -0,0 +1,151 @@ +package filter_and_search + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Filter in the several nested panels and verify the filters are preserved as you escape back to the surface", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + // need to create some branches, each with their own commits + shell.NewBranch("branch-gold") + shell.CreateFileAndAdd("apple", "apple") + shell.CreateFileAndAdd("orange", "orange") + shell.CreateFileAndAdd("grape", "grape") + shell.Commit("commit-knife") + + shell.NewBranch("branch-silver") + shell.UpdateFileAndAdd("apple", "apple-2") + shell.UpdateFileAndAdd("orange", "orange-2") + shell.UpdateFileAndAdd("grape", "grape-2") + shell.Commit("commit-spoon") + + shell.NewBranch("branch-bronze") + shell.UpdateFileAndAdd("apple", "apple-3") + shell.UpdateFileAndAdd("orange", "orange-3") + shell.UpdateFileAndAdd("grape", "grape-3") + shell.Commit("commit-fork") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Focus(). + Lines( + Contains(`branch-bronze`).IsSelected(), + Contains(`branch-silver`), + Contains(`branch-gold`), + ). + FilterOrSearch("sil"). + Lines( + Contains(`branch-silver`).IsSelected(), + ). + PressEnter() + + t.Views().SubCommits(). + IsFocused(). + Lines( + Contains(`commit-spoon`).IsSelected(), + Contains(`commit-knife`), + ). + FilterOrSearch("knife"). + Lines( + // sub-commits view searches, it doesn't filter, so we haven't filtered down the list + Contains(`commit-spoon`), + Contains(`commit-knife`).IsSelected(), + ). + PressEnter() + + t.Views().CommitFiles(). + IsFocused(). + Lines( + Contains(`apple`).IsSelected(), + Contains(`grape`), + Contains(`orange`), + ). + FilterOrSearch("grape"). + Lines( + Contains(`apple`), + Contains(`grape`).IsSelected(), + Contains(`orange`), + ). + PressEnter() + + t.Views().PatchBuilding(). + IsFocused(). + FilterOrSearch("newline"). + SelectedLine(Contains("No newline at end of file")). + PressEscape(). // cancel search + Tap(func() { + t.Views().Search().IsInvisible() + }). + // escape to commit-files view + PressEscape() + + t.Views().CommitFiles(). + IsFocused(). + Lines( + Contains(`apple`), + Contains(`grape`).IsSelected(), + Contains(`orange`), + ). + Tap(func() { + t.Views().Search().IsVisible().Content(Contains("matches for 'grape'")) + }). + // cancel search + PressEscape(). + Tap(func() { + t.Views().Search().IsInvisible() + }). + Lines( + Contains(`apple`), + Contains(`grape`).IsSelected(), + Contains(`orange`), + ). + // escape to sub-commits view + PressEscape() + + t.Views().SubCommits(). + IsFocused(). + Lines( + Contains(`commit-spoon`), + Contains(`commit-knife`).IsSelected(), + ). + Tap(func() { + t.Views().Search().IsVisible().Content(Contains("matches for 'knife'")) + }). + // cancel search + PressEscape(). + Tap(func() { + t.Views().Search().IsInvisible() + }). + Lines( + Contains(`commit-spoon`), + // still selected + Contains(`commit-knife`).IsSelected(), + ). + // escape to branches view + PressEscape() + + t.Vi |