summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2022-12-27 16:27:36 +1100
committerJesse Duffield <jessedduffield@gmail.com>2022-12-27 21:26:18 +1100
commitb166b8f776e45c77a94b6e919f3b9460ff3c2e06 (patch)
tree17459acf768779d92bae318fa631b2cc43aeb472
parentc5c9f5bb941342766f86626ad13d30e5ce01980e (diff)
combine assert and input structs, clean up interface
-rw-r--r--pkg/integration/README.md4
-rw-r--r--pkg/integration/components/alert_asserter.go9
-rw-r--r--pkg/integration/components/assert.go38
-rw-r--r--pkg/integration/components/commit_message_panel_asserter.go13
-rw-r--r--pkg/integration/components/confirmation_asserter.go9
-rw-r--r--pkg/integration/components/input.go174
-rw-r--r--pkg/integration/components/menu_asserter.go11
-rw-r--r--pkg/integration/components/model.go24
-rw-r--r--pkg/integration/components/prompt_asserter.go29
-rw-r--r--pkg/integration/components/test.go8
-rw-r--r--pkg/integration/components/test_test.go20
-rw-r--r--pkg/integration/components/view.go196
-rw-r--r--pkg/integration/components/views.go174
-rw-r--r--pkg/integration/tests/bisect/basic.go45
-rw-r--r--pkg/integration/tests/bisect/from_other_branch.go34
-rw-r--r--pkg/integration/tests/branch/checkout_by_name.go25
-rw-r--r--pkg/integration/tests/branch/delete.go29
-rw-r--r--pkg/integration/tests/branch/rebase.go50
-rw-r--r--pkg/integration/tests/branch/rebase_and_drop.go77
-rw-r--r--pkg/integration/tests/branch/reset.go35
-rw-r--r--pkg/integration/tests/branch/suggestions.go12
-rw-r--r--pkg/integration/tests/cherry_pick/cherry_pick.go89
-rw-r--r--pkg/integration/tests/cherry_pick/cherry_pick_conflicts.go121
-rw-r--r--pkg/integration/tests/commit/commit.go20
-rw-r--r--pkg/integration/tests/commit/commit_multiline.go20
-rw-r--r--pkg/integration/tests/commit/new_branch.go28
-rw-r--r--pkg/integration/tests/commit/revert.go24
-rw-r--r--pkg/integration/tests/commit/staged.go51
-rw-r--r--pkg/integration/tests/commit/staged_without_hooks.go39
-rw-r--r--pkg/integration/tests/commit/unstaged.go39
-rw-r--r--pkg/integration/tests/config/remote_named_star.go3
-rw-r--r--pkg/integration/tests/custom_commands/basic.go14
-rw-r--r--pkg/integration/tests/custom_commands/form_prompts.go19
-rw-r--r--pkg/integration/tests/custom_commands/menu_from_command.go20
-rw-r--r--pkg/integration/tests/custom_commands/menu_from_commands_output.go17
-rw-r--r--pkg/integration/tests/custom_commands/multiple_prompts.go19
-rw-r--r--pkg/integration/tests/diff/diff.go83
-rw-r--r--pkg/integration/tests/diff/diff_and_apply_patch.go76
-rw-r--r--pkg/integration/tests/diff/diff_commits.go47
-rw-r--r--pkg/integration/tests/file/dir_with_untracked_file.go6
-rw-r--r--pkg/integration/tests/file/discard_changes.go17
-rw-r--r--pkg/integration/tests/interactive_rebase/amend_merge.go21
-rw-r--r--pkg/integration/tests/interactive_rebase/one.go99
-rw-r--r--pkg/integration/tests/misc/confirm_on_quit.go11
-rw-r--r--pkg/integration/tests/stash/rename.go22
-rw-r--r--pkg/integration/tests/stash/stash.go17
-rw-r--r--pkg/integration/tests/stash/stash_including_untracked_files.go17
47 files changed, 1032 insertions, 923 deletions
diff --git a/pkg/integration/README.md b/pkg/integration/README.md
index d05e45f0c..fe4f43ac1 100644
--- a/pkg/integration/README.md
+++ b/pkg/integration/README.md
@@ -48,8 +48,8 @@ Try to do as much setup work as possible in your setup step. For example, if all
Use assertions to ensure that lazygit has processed all your keybindings so far. Each time you press a key, something should happen on the screen, so you should assert that that thing has happened. This means we won't get into trouble from keys being entered two quickly because at each stage we ensure the key has been processed. This also makes tests more readable because they help explain what we expect to be happening on-screen. For example:
```go
-input.Press(keys.Files.CommitChanges)
-assert.InCommitMessagePanel()
+input.press(keys.Files.CommitChanges)
+input.InCommitMessagePanel()
```
Note that there are some `input` methods that have assertions baked in, such as the `SwitchToView` methods.
diff --git a/pkg/integration/components/alert_asserter.go b/pkg/integration/components/alert_asserter.go
index 739f44256..abc2f1171 100644
--- a/pkg/integration/components/alert_asserter.go
+++ b/pkg/integration/components/alert_asserter.go
@@ -1,14 +1,13 @@
package components
type AlertAsserter struct {
- assert *Assert
input *Input
hasCheckedTitle bool
hasCheckedContent bool
}
func (self *AlertAsserter) getViewAsserter() *View {
- return self.assert.Views().ByName("confirmation")
+ return self.input.Views().Confirmation()
}
// asserts that the alert view has the expected title
@@ -32,17 +31,17 @@ func (self *AlertAsserter) Content(expected *matcher) *AlertAsserter {
func (self *AlertAsserter) Confirm() {
self.checkNecessaryChecksCompleted()
- self.input.Confirm()
+ self.getViewAsserter().PressEnter()
}
func (self *AlertAsserter) Cancel() {
self.checkNecessaryChecksCompleted()
- self.input.Press(self.input.keys.Universal.Return)
+ self.getViewAsserter().PressEscape()
}
func (self *AlertAsserter) checkNecessaryChecksCompleted() {
if !self.hasCheckedContent || !self.hasCheckedTitle {
- self.assert.Fail("You must both check the content and title of a confirmation popup by calling Title()/Content() before calling Confirm()/Cancel().")
+ self.input.Fail("You must both check the content and title of a confirmation popup by calling Title()/Content() before calling Confirm()/Cancel().")
}
}
diff --git a/pkg/integration/components/assert.go b/pkg/integration/components/assert.go
deleted file mode 100644
index 531e4f4dc..000000000
--- a/pkg/integration/components/assert.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package components
-
-import (
- integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
-)
-
-// through this struct we assert on the state of the lazygit gui
-
-type Assert struct {
- input *Input
- gui integrationTypes.GuiDriver
- *assertionHelper
-}
-
-func NewAssert(gui integrationTypes.GuiDriver) *Assert {
- return &Assert{gui: gui}
-}
-
-// for making assertions on lazygit views
-func (self *Assert) Views() *Views {
- return &Views{assert: self, input: self.input}
-}
-
-// for making assertions on the lazygit model
-func (self *Assert) Model() *Model {
- return &Model{assertionHelper: self.assertionHelper, gui: self.gui}
-}
-
-// for making assertions on the file system
-func (self *Assert) FileSystem() *FileSystem {
- return &FileSystem{assertionHelper: self.assertionHelper}
-}
-
-// for when you just want to fail the test yourself.
-// This runs callbacks to ensure we render the error after closing the gui.
-func (self *Assert) Fail(message string) {
- self.assertionHelper.fail(message)
-}
diff --git a/pkg/integration/components/commit_message_panel_asserter.go b/pkg/integration/components/commit_message_panel_asserter.go
index 2d9ef834a..9aacacf89 100644
--- a/pkg/integration/components/commit_message_panel_asserter.go
+++ b/pkg/integration/components/commit_message_panel_asserter.go
@@ -1,12 +1,11 @@
package components
type CommitMessagePanelAsserter struct {
- assert *Assert
- input *Input
+ input *Input
}
func (self *CommitMessagePanelAsserter) getViewAsserter() *View {
- return self.assert.Views().ByName("commitMessage")
+ return self.input.Views().CommitMessage()
}
// asserts on the text initially present in the prompt
@@ -17,13 +16,13 @@ func (self *CommitMessagePanelAsserter) InitialText(expected *matcher) *CommitMe
}
func (self *CommitMessagePanelAsserter) Type(value string) *CommitMessagePanelAsserter {
- self.input.Type(value)
+ self.input.typeContent(value)
return self
}
func (self *CommitMessagePanelAsserter) AddNewline() *CommitMessagePanelAsserter {
- self.input.Press(self.input.keys.Universal.AppendNewline)
+ self.input.press(self.input.keys.Universal.AppendNewline)
return self
}
@@ -33,9 +32,9 @@ func (self *CommitMessagePanelAsserter) Clear() *CommitMessagePanelAsserter {
}
func (self *CommitMessagePanelAsserter) Confirm() {
- self.input.Confirm()
+ self.getViewAsserter().PressEnter()
}
func (self *CommitMessagePanelAsserter) Cancel() {
- self.input.Press(self.input.keys.Universal.Return)
+ self.getViewAsserter().PressEscape()
}
diff --git a/pkg/integration/components/confirmation_asserter.go b/pkg/integration/components/confirmation_asserter.go
index 4fe64fdb0..2d3d87ba0 100644
--- a/pkg/integration/components/confirmation_asserter.go
+++ b/pkg/integration/components/confirmation_asserter.go
@@ -1,14 +1,13 @@
package components
type ConfirmationAsserter struct {
- assert *Assert
input *Input
hasCheckedTitle bool
hasCheckedContent bool
}
func (self *ConfirmationAsserter) getViewAsserter() *View {
- return self.assert.Views().ByName("confirmation")
+ return self.input.Views().Confirmation()
}
// asserts that the confirmation view has the expected title
@@ -32,17 +31,17 @@ func (self *ConfirmationAsserter) Content(expected *matcher) *ConfirmationAssert
func (self *ConfirmationAsserter) Confirm() {
self.checkNecessaryChecksCompleted()
- self.input.Confirm()
+ self.getViewAsserter().PressEnter()
}
func (self *ConfirmationAsserter) Cancel() {
self.checkNecessaryChecksCompleted()
- self.input.Press(self.input.keys.Universal.Return)
+ self.getViewAsserter().PressEscape()
}
func (self *ConfirmationAsserter) checkNecessaryChecksCompleted() {
if !self.hasCheckedContent || !self.hasCheckedTitle {
- self.assert.Fail("You must both check the content and title of a confirmation popup by calling Title()/Content() before calling Confirm()/Cancel().")
+ self.input.Fail("You must both check the content and title of a confirmation popup by calling Title()/Content() before calling Confirm()/Cancel().")
}
}
diff --git a/pkg/integration/components/input.go b/pkg/integration/components/input.go
index d525c61c6..d5db33518 100644
--- a/pkg/integration/components/input.go
+++ b/pkg/integration/components/input.go
@@ -8,14 +8,14 @@ import (
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
+ "github.com/samber/lo"
)
type Input struct {
- gui integrationTypes.GuiDriver
- keys config.KeybindingConfig
- assert *Assert
- *assertionHelper
+ gui integrationTypes.GuiDriver
+ keys config.KeybindingConfig
pushKeyDelay int
+ *assertionHelper
}
func NewInput(gui integrationTypes.GuiDriver, keys config.KeybindingConfig, pushKeyDelay int) *Input {
@@ -23,119 +23,31 @@ func NewInput(gui integrationTypes.GuiDriver, keys config.KeybindingConfig, push
gui: gui,
keys: keys,
pushKeyDelay: pushKeyDelay,
- assertionHelper: assert.assertionHelper,
+ assertionHelper: &assertionHelper{gui: gui},
}
}
// key is something like 'w' or '<space>'. It's best not to pass a direct value,
// but instead to go through the default user config to get a more meaningful key name
-func (self *Input) Press(keyStrs ...string) {
- for _, keyStr := range keyStrs {
- self.press(keyStr)
- }
-}
-
func (self *Input) press(keyStr string) {
self.Wait(self.pushKeyDelay)
self.gui.PressKey(keyStr)
}
-func (self *Input) SwitchToStatusWindow() {
- self.press(self.keys.Universal.JumpToBlock[0])
- self.currentWindowName("status")
-}
-
-// switch to status window and assert that the status view is on top
-func (self *Input) SwitchToStatusView() {
- self.SwitchToStatusWindow()
- self.assert.Views().Current().Name("status")
-}
-
-func (self *Input) switchToFilesWindow() {
- self.press(self.keys.Universal.JumpToBlock[1])
- self.currentWindowName("files")
-}
-
-// switch to files window and assert that the files view is on top
-func (self *Input) SwitchToFilesView() {
- self.switchToFilesWindow()
- self.assert.Views().Current().Name("files")
-}
-
-func (self *Input) SwitchToBranchesWindow() {
- self.press(self.keys.Universal.JumpToBlock[2])
- self.currentWindowName("localBranches")
-}
-
-// switch to branches window and assert that the branches view is on top
-func (self *Input) SwitchToBranchesView() {
- self.SwitchToBranchesWindow()
- self.assert.Views().Current().Name("localBranches")
-}
-
-func (self *Input) SwitchToCommitsWindow() {
- self.press(self.keys.Universal.JumpToBlock[3])
- self.currentWindowName("commits")
-}
-
-// switch to commits window and assert that the commits view is on top
-func (self *Input) SwitchToCommitsView() {
- self.SwitchToCommitsWindow()
- self.assert.Views().Current().Name("commits")
-}
-
-func (self *Input) SwitchToStashWindow() {
- self.press(self.keys.Universal.JumpToBlock[4])
- self.currentWindowName("stash")
-}
-
-// switch to stash window and assert that the stash view is on top
-func (self *Input) SwitchToStashView() {
- self.SwitchToStashWindow()
- self.assert.Views().Current().Name("stash")
-}
-
-func (self *Input) Type(content string) {
+func (self *Input) typeContent(content string) {
for _, char := range content {
self.press(string(char))
}
}
-// i.e. pressing enter
-func (self *Input) Confirm() {
- self.press(self.keys.Universal.Confirm)
-}
-
-// i.e. same as Confirm
-func (self *Input) Enter() {
- self.press(self.keys.Universal.Confirm)
-}
-
-// i.e. pressing escape
-func (self *Input) Cancel() {
- self.press(self.keys.Universal.Return)
-}
-
-// i.e. pressing space
-func (self *Input) PrimaryAction() {
- self.press(self.keys.Universal.Select)
-}
-
-// i.e. pressing down arrow
-func (self *Input) NextItem() {
- self.press(self.keys.Universal.NextItem)
-}
-
-// i.e. pressing up arrow
-func (self *Input) PreviousItem() {
- self.press(self.keys.Universal.PrevItem)
-}
-
func (self *Input) ContinueMerge() {
- self.Press(self.keys.Universal.CreateRebaseOptionsMenu)
- self.assert.Views().Current().SelectedLine(Contains("continue"))
- self.Confirm()
+ self.Views().current().Press(self.keys.Universal.CreateRebaseOptionsMenu)
+
+ self.ExpectMenu().
+ Title(Equals("Rebase Options")).
+ Select(Contains("continue")).
+ Confirm()
}
func (self *Input) ContinueRebase() {
@@ -166,7 +78,7 @@ func (self *Input) Log(message string) {
// If this changes in future, we'll need to update this code to first attempt to find the item
// in the current page and failing that, jump to the top of the view and iterate through all of it,
// looking for the item.
-func (self *Input) NavigateToListItem(matcher *matcher) {
+func (self *Input) navigateToListItem(matcher *matcher) {
self.inListContext()
currentContext := self.gui.CurrentContext().(types.IListContext)
@@ -175,7 +87,7 @@ func (self *Input) NavigateToListItem(matcher *matcher) {
var matchIndex int
- self.assert.assertWithRetries(func() (bool, string) {
+ self.assertWithRetries(func() (bool, string) {
matchIndex = -1
var matches []string
lines := view.ViewBufferLines()
@@ -198,20 +110,20 @@ func (self *Input) NavigateToListItem(matcher *matcher) {
selectedLineIdx := view.SelectedLineIdx()
if selectedLineIdx == matchIndex {
- self.assert.Views().Current().SelectedLine(matcher)
+ self.Views().current().SelectedLine(matcher)
return
}
if selectedLineIdx < matchIndex {
for i := selectedLineIdx; i < matchIndex; i++ {
- self.NextItem()
+ self.Views().current().SelectNextItem()
}
- self.assert.Views().Current().SelectedLine(matcher)
+ self.Views().current().SelectedLine(matcher)
return
} else {
for i := selectedLineIdx; i > matchIndex; i-- {
- self.PreviousItem()
+ self.Views().current().SelectPreviousItem()
}
- self.assert.Views().Current().SelectedLine(matcher)
+ self.Views().current().SelectedLine(matcher)
return
}
}
@@ -224,10 +136,10 @@ func (self *Input) inListContext() {
})
}
-func (self *Input) Confirmation() *ConfirmationAsserter {
+func (self *Input) ExpectConfirmation() *ConfirmationAsserter {
self.inConfirm()
- return &ConfirmationAsserter{assert: self.assert, input: self}
+ return &ConfirmationAsserter{input: self}
}
func (self *Input) inConfirm() {
@@ -237,10 +149,10 @@ func (self *Input) inConfirm() {
})
}
-func (self *Input) Prompt() *PromptAsserter {
+func (self *Input) ExpectPrompt() *PromptAsserter {
self.inPrompt()
- return &PromptAsserter{assert: self.assert, input: self}
+ return &PromptAsserter{input: self}
}
func (self *Input) inPrompt() {
@@ -250,10 +162,10 @@ func (self *Input) inPrompt() {
})
}
-func (self *Input) Alert() *AlertAsserter {
+func (self *Input) ExpectAlert() *AlertAsserter {
self.inAlert()
- return &AlertAsserter{assert: self.assert, input: self}
+ return &AlertAsserter{input: self}
}
func (self *Input) inAlert() {
@@ -264,10 +176,10 @@ func (self *Input) inAlert() {
})
}
-func (self *Input) Menu() *MenuAsserter {
+func (self *Input) ExpectMenu() *MenuAsserter {
self.inMenu()
- return &MenuAsserter{assert: self.assert, input: self}
+ return &MenuAsserter{input: self}
}
func (self *Input) inMenu() {
@@ -276,10 +188,10 @@ func (self *Input) inMenu() {
})
}
-func (self *Input) CommitMessagePanel() *CommitMessagePanelAsserter {
+func (self *Input) ExpectCommitMessagePanel() *CommitMessagePanelAsserter {
self.inCommitMessagePanel()
- return &CommitMessagePanelAsserter{assert: self.assert, input: self}
+ return &CommitMessagePanelAsserter{input: self}
}
func (self *Input) inCommitMessagePanel() {
@@ -295,3 +207,31 @@ func (self *Input) currentWindowName(expectedWindowName string) {
return actual == expectedWindowName, fmt.Sprintf("Expected current window name to be '%s', but got '%s'", expectedWindowName, actual)
})
}
+
+// for making assertions on lazygit views
+func (self *Input) Views() *Views {
+ return &Views{input: self}
+}
+
+// for making assertions on the lazygit model
+func (self *Input) Model() *Model {
+ return &Model{assertionHelper: self.assertionHelper, gui: self.gui}
+}
+
+// for making assertions on the file system
+func (self *Input) FileSystem() *FileSystem {
+ return &FileSystem{assertionHelper: self.assertionHelper}
+}
+
+// for when you just want to fail the test yourself.
+// This runs callbacks to ensure we render the error after closing the gui.
+func (self *Input) Fail(message string) {
+ self.assertionHelper.fail(message)
+}
+
+func (self *Input) NotInPopup() {
+ self.assertWithRetries(func() (bool, string) {
+ viewName := self.gui.CurrentContext().GetView().Name()
+ return !lo.Contains([]string{"menu", "confirmation", "commitMessage"}, viewName), fmt.Sprintf("Unexpected popup view present: %s view", viewName)
+ })
+}
diff --git a/pkg/integration/components/menu_asserter.go b/pkg/integration/components/menu_asserter.go
index 32191ac08..4f1fd035a 100644
--- a/pkg/integration/components/menu_asserter.go
+++ b/pkg/integration/components/menu_asserter.go
@@ -1,13 +1,12 @@
package components
type MenuAsserter struct {
- assert *Assert
input *Input
hasCheckedTitle bool
}
func (self *MenuAsserter) getViewAsserter() *View {
- return self.assert.Views().ByName("menu")
+ return self.input.Views().Menu()
}
// asserts that the popup has the expected title
@@ -22,23 +21,23 @@ func (self *MenuAsserter) Title(expected *matcher) *MenuAsserter {
func (self *MenuAsserter) Confirm() {
self.checkNecessaryChecksCompleted()
- self.input.Confirm()
+ self.getViewAsserter().PressEnter()
}
func (self *MenuAsserter) Cancel() {
self.checkNecessaryChecksCompleted()
- self.input.Press(self.input.keys.Universal.Return)
+ self.getViewAsserter().PressEscape()
}
func (self *MenuAsserter) Select(option *matcher) *MenuAsserter {
- self.input.NavigateToListItem(option)
+ self.getViewAsserter().NavigateToListItem(option)
return self
}
func (self *MenuAsserter) checkNecessaryChecksCompleted() {
if !self.hasCheckedTitle {
- self.assert.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")
+ self.input.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")
}
}
diff --git a/pkg/integration/components/model.go b/pkg/integration/components/model.go
index 83d2e97e8..368c50852 100644
--- a/pkg/integration/components/model.go
+++ b/pkg/integration/components/model.go
@@ -11,7 +11,7 @@ type Model struct {
gui integrationTypes.GuiDriver
}
-func (self *Model) WorkingTreeFileCount(expectedCount int) {
+func (self *Model) WorkingTreeFileCount(expectedCount int) *Model {
self.assertWithRetries(func() (bool, string) {
actualCount := len(self.gui.Model().Files)
@@ -20,9 +20,11 @@ func (self *Model) WorkingTreeFileCount(expectedCount int) {
expectedCount, actualCount,
)
})
+
+ return self
}
-func (self *Model) CommitCount(expectedCount int) {
+func (self *Model) CommitCount(expectedCount int) *Model {
self.assertWithRetries(func() (bool, string) {
actualCount := len(self.gui.Model().Commits)
@@ -31,9 +33,11 @@ func (self *Model) CommitCount(expectedCount int) {
expectedCount, actualCount,
)
})
+
+ return self
}
-func (self *Model) StashCount(expectedCount int) {
+func (self *Model) StashCount(expectedCount int) *Model {
self.assertWithRetries(func() (bool, string) {
actualCount := len(self.gui.Model().StashEntries)
@@ -42,17 +46,21 @@ func (self *Model) StashCount(expectedCount int) {
expectedCount, actualCount,
)
})
+
+ return self
}
-func (self *Model) AtLeastOneCommit() {
+func (self *Model) AtLeastOneCommit() *Model {
self.assertWithRetries(func() (bool, string) {
actualCount := len(self.gui.Model().Commits)
return actualCount > 0, "Expected at least one commit present"
})
+
+ return self
}
-func (self *Model) HeadCommitMessage(matcher *matcher) {
+func (self *Model) HeadCommitMessage(matcher *matcher) *Model {
self.assertWithRetries(func() (bool, string) {
return len(self.gui.Model().Commits) > 0, "Expected at least one commit to be present"
})
@@ -62,11 +70,15 @@ func (self *Model) HeadCommitMessage(matcher *matcher) {
return self.gui.Model().Commits[0].Name
},
)
+
+ return self
}
-func (self *Model) CurrentBranchName(expectedViewName string) {
+func (self *Model) CurrentBranchName(expectedViewName string) *Model {
self.assertWithRetries(func() (bool, string) {
actual := self.gui.CheckedOutRef().Name
return actual == expectedViewName, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expectedViewName, actual)
})
+
+ return self
}
diff --git a/pkg/integration/components/prompt_asserter.go b/pkg/integration/components/prompt_asserter.go
index fe7749e14..343d9d54b 100644
--- a/