mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Add integration tests for searching/filtering
This commit is contained in:
		| @@ -201,7 +201,6 @@ func (self *ContextMgr) deactivateContext(c types.Context, opts types.OnFocusLos | ||||
| 	view, _ := self.gui.c.GocuiGui().View(c.GetViewName()) | ||||
|  | ||||
| 	if opts.NewContextKey != context.SEARCH_CONTEXT_KEY { | ||||
| 		self.gui.helpers.Search.HidePrompt() | ||||
| 		if c.GetKind() == types.MAIN_CONTEXT || c.GetKind() == types.TEMPORARY_POPUP { | ||||
| 			self.gui.helpers.Search.CancelSearchIfSearching(c) | ||||
| 		} | ||||
| @@ -235,7 +234,7 @@ func (self *ContextMgr) ActivateContext(c types.Context, opts types.OnFocusOpts) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	self.gui.helpers.Search.DisplaySearchStatusIfSearching(c) | ||||
| 	self.gui.helpers.Search.RenderSearchStatus(c) | ||||
|  | ||||
| 	desiredTitle := c.Title() | ||||
| 	if desiredTitle != "" { | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/jesseduffield/gocui" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/context" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/keybindings" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/types" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/theme" | ||||
| @@ -198,19 +199,27 @@ func (self *SearchHelper) OnPromptContentChanged(searchString string) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (self *SearchHelper) DisplaySearchStatusIfSearching(c types.Context) { | ||||
| func (self *SearchHelper) RenderSearchStatus(c types.Context) { | ||||
| 	if c.GetKey() == context.SEARCH_CONTEXT_KEY { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if searchableContext, ok := c.(types.ISearchableContext); ok { | ||||
| 		if searchableContext.IsSearching() { | ||||
| 			self.setSearchingFrameColor() | ||||
| 			self.DisplaySearchStatus(searchableContext) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if filterableContext, ok := c.(types.IFilterableContext); ok { | ||||
| 		if filterableContext.IsFiltering() { | ||||
| 			self.setSearchingFrameColor() | ||||
| 			self.DisplayFilterStatus(filterableContext) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	self.HidePrompt() | ||||
| } | ||||
|  | ||||
| func (self *SearchHelper) CancelSearchIfSearching(c types.Context) { | ||||
|   | ||||
| @@ -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) | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
|   | ||||
| @@ -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().") | ||||
|   | ||||
| @@ -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,33 +470,60 @@ 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) { | ||||
| 		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)) | ||||
| 		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() | ||||
|  | ||||
| 		// 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 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) { | ||||
| 		return !self.getView().Visible, fmt.Sprintf("%s: Expected view to be visible, but it was not", self.context) | ||||
| 	}) | ||||
|  | ||||
| 	return self | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| } | ||||
|  | ||||
| // for when you want to make some assertion unrelated to the current view | ||||
| // without breaking the method chain | ||||
| func (self *ViewDriver) Tap(f func()) *ViewDriver { | ||||
|   | ||||
| @@ -42,6 +42,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ | ||||
| 			Press(keys.Universal.StartSearch). | ||||
| 			Tap(func() { | ||||
| 				t.ExpectSearch(). | ||||
| 					Clear(). | ||||
| 					Type("o"). | ||||
| 					Confirm() | ||||
|  | ||||
|   | ||||
| @@ -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:         false, | ||||
| 	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`), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
							
								
								
									
										76
									
								
								pkg/integration/tests/filter_and_search/filter_files.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								pkg/integration/tests/filter_and_search/filter_files.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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:         false, | ||||
| 	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`), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
							
								
								
									
										48
									
								
								pkg/integration/tests/filter_and_search/filter_menu.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								pkg/integration/tests/filter_and_search/filter_menu.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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)) | ||||
| 			}) | ||||
| 	}, | ||||
| }) | ||||
							
								
								
									
										147
									
								
								pkg/integration/tests/filter_and_search/nested_filter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								pkg/integration/tests/filter_and_search/nested_filter.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| 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(`grape`).IsSelected(), | ||||
| 			). | ||||
| 			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(`grape`).IsSelected(), | ||||
| 			). | ||||
| 			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.Views().Branches(). | ||||
| 			IsFocused(). | ||||
| 			Lines( | ||||
| 				Contains(`branch-silver`).IsSelected(), | ||||
| 			). | ||||
| 			Tap(func() { | ||||
| 				t.Views().Search().IsVisible().Content(Contains("matches for 'sil'")) | ||||
| 			}). | ||||
| 			// cancel search | ||||
| 			PressEscape(). | ||||
| 			Tap(func() { | ||||
| 				t.Views().Search().IsInvisible() | ||||
| 			}). | ||||
| 			Lines( | ||||
| 				Contains(`branch-bronze`), | ||||
| 				Contains(`branch-silver`).IsSelected(), | ||||
| 				Contains(`branch-gold`), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
| @@ -0,0 +1,105 @@ | ||||
| package filter_and_search | ||||
|  | ||||
| import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/config" | ||||
| 	. "github.com/jesseduffield/lazygit/pkg/integration/components" | ||||
| ) | ||||
|  | ||||
| // This one requires some explanation: the sub-commits and diff-file contexts are | ||||
| // 'transient' in that they are spawned inside a window when you need them, but | ||||
| // can be relocated elsewhere if you need them somewhere else. So for example if | ||||
| // I hit enter on a branch I'll see the sub-commits view, but if I then navigate | ||||
| // to the reflog context and hit enter on a reflog, the sub-commits view is moved | ||||
| // to the reflog window. This is because we re-use the same view (it's a limitation | ||||
| // that would be nice to remove in the future). | ||||
| // Nonetheless, we need to ensure that upon moving the view, the filter is cancelled. | ||||
|  | ||||
| var NestedFilterTransient = NewIntegrationTest(NewIntegrationTestArgs{ | ||||
| 	Description:  "Filter in a transient panel (sub-commits and diff-files) and ensure filter is cancelled when the panel is moved", | ||||
| 	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("mybranch") | ||||
| 		shell.CreateFileAndAdd("file-one", "file-one") | ||||
| 		shell.CreateFileAndAdd("file-two", "file-two") | ||||
| 		shell.Commit("commit-one") | ||||
| 		shell.EmptyCommit("commit-two") | ||||
| 	}, | ||||
| 	Run: func(t *TestDriver, keys config.KeybindingConfig) { | ||||
| 		t.Views().Branches(). | ||||
| 			Focus(). | ||||
| 			Lines( | ||||
| 				Contains(`mybranch`).IsSelected(), | ||||
| 			). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().SubCommits(). | ||||
| 			IsFocused(). | ||||
| 			Lines( | ||||
| 				Contains(`commit-two`).IsSelected(), | ||||
| 				Contains(`commit-one`), | ||||
| 			). | ||||
| 			FilterOrSearch("one"). | ||||
| 			Lines( | ||||
| 				Contains(`commit-two`), | ||||
| 				Contains(`commit-one`).IsSelected(), | ||||
| 			) | ||||
|  | ||||
| 		t.Views().ReflogCommits(). | ||||
| 			Focus(). | ||||
| 			SelectedLine(Contains("commit: commit-two")). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().SubCommits(). | ||||
| 			IsFocused(). | ||||
| 			// the search on the sub-commits context has been cancelled | ||||
| 			Lines( | ||||
| 				Contains(`commit-two`).IsSelected(), | ||||
| 				Contains(`commit-one`), | ||||
| 			). | ||||
| 			Tap(func() { | ||||
| 				t.Views().Search().IsInvisible() | ||||
| 			}). | ||||
| 			NavigateToLine(Contains("commit-one")). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		// Now let's test the commit files context | ||||
| 		t.Views().CommitFiles(). | ||||
| 			IsFocused(). | ||||
| 			Lines( | ||||
| 				Contains(`file-one`).IsSelected(), | ||||
| 				Contains(`file-two`), | ||||
| 			). | ||||
| 			FilterOrSearch("one"). | ||||
| 			Lines( | ||||
| 				Contains(`file-one`).IsSelected(), | ||||
| 			) | ||||
|  | ||||
| 		t.Views().Branches(). | ||||
| 			Focus(). | ||||
| 			SelectedLine(Contains("mybranch")). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().SubCommits(). | ||||
| 			IsFocused(). | ||||
| 			Lines( | ||||
| 				Contains(`commit-two`).IsSelected(), | ||||
| 				Contains(`commit-one`), | ||||
| 			). | ||||
| 			NavigateToLine(Contains("commit-one")). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().CommitFiles(). | ||||
| 			IsFocused(). | ||||
| 			// the search on the commit-files context has been cancelled | ||||
| 			Lines( | ||||
| 				Contains(`file-one`).IsSelected(), | ||||
| 				Contains(`file-two`), | ||||
| 			). | ||||
| 			Tap(func() { | ||||
| 				t.Views().Search().IsInvisible() | ||||
| 			}) | ||||
| 	}, | ||||
| }) | ||||
| @@ -13,6 +13,7 @@ import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/diff" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/file" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_and_search" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/misc" | ||||
| @@ -94,6 +95,11 @@ var tests = []*components.IntegrationTest{ | ||||
| 	file.DiscardUnstagedFileChanges, | ||||
| 	file.Gitignore, | ||||
| 	file.RememberCommitMessageAfterFail, | ||||
| 	filter_and_search.FilterCommitFiles, | ||||
| 	filter_and_search.FilterFiles, | ||||
| 	filter_and_search.FilterMenu, | ||||
| 	filter_and_search.NestedFilter, | ||||
| 	filter_and_search.NestedFilterTransient, | ||||
| 	filter_by_path.CliArg, | ||||
| 	filter_by_path.SelectFile, | ||||
| 	filter_by_path.TypeFile, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user