From b8d944399901685e5edc1bded23457db0dd283c5 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Fri, 12 Aug 2022 09:19:39 +1000 Subject: rename helpers to components --- pkg/integration/components/assert.go | 111 ++++++++++++++++ pkg/integration/components/input.go | 166 ++++++++++++++++++++++++ pkg/integration/components/shell.go | 83 ++++++++++++ pkg/integration/components/test.go | 118 +++++++++++++++++ pkg/integration/helpers/assert.go | 111 ---------------- pkg/integration/helpers/input.go | 166 ------------------------ pkg/integration/helpers/shell.go | 83 ------------ pkg/integration/helpers/test.go | 118 ----------------- pkg/integration/integration.go | 10 +- pkg/integration/integration_test.go | 3 +- pkg/integration/runner/main.go | 7 +- pkg/integration/tests/branch/suggestions.go | 8 +- pkg/integration/tests/commit/commit.go | 8 +- pkg/integration/tests/commit/new_branch.go | 8 +- pkg/integration/tests/interactive_rebase/one.go | 8 +- pkg/integration/tests/tests.go | 4 +- pkg/integration/tui/main.go | 5 +- 17 files changed, 507 insertions(+), 510 deletions(-) create mode 100644 pkg/integration/components/assert.go create mode 100644 pkg/integration/components/input.go create mode 100644 pkg/integration/components/shell.go create mode 100644 pkg/integration/components/test.go delete mode 100644 pkg/integration/helpers/assert.go delete mode 100644 pkg/integration/helpers/input.go delete mode 100644 pkg/integration/helpers/shell.go delete mode 100644 pkg/integration/helpers/test.go (limited to 'pkg') diff --git a/pkg/integration/components/assert.go b/pkg/integration/components/assert.go new file mode 100644 index 000000000..11048532d --- /dev/null +++ b/pkg/integration/components/assert.go @@ -0,0 +1,111 @@ +package components + +import ( + "fmt" + "strings" + "time" + + "github.com/jesseduffield/lazygit/pkg/gui/types" + integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" +) + +// through this struct we assert on the state of the lazygit gui + +type Assert struct { + gui integrationTypes.GuiAdapter +} + +func NewAssert(gui integrationTypes.GuiAdapter) *Assert { + return &Assert{gui: gui} +} + +func (self *Assert) WorkingTreeFileCount(expectedCount int) { + self.assertWithRetries(func() (bool, string) { + actualCount := len(self.gui.Model().Files) + + return actualCount == expectedCount, fmt.Sprintf( + "Expected %d changed working tree files, but got %d", + expectedCount, actualCount, + ) + }) +} + +func (self *Assert) CommitCount(expectedCount int) { + self.assertWithRetries(func() (bool, string) { + actualCount := len(self.gui.Model().Commits) + + return actualCount == expectedCount, fmt.Sprintf( + "Expected %d commits present, but got %d", + expectedCount, actualCount, + ) + }) +} + +func (self *Assert) HeadCommitMessage(expectedMessage string) { + self.assertWithRetries(func() (bool, string) { + if len(self.gui.Model().Commits) == 0 { + return false, "Expected at least one commit to be present" + } + + headCommit := self.gui.Model().Commits[0] + if headCommit.Name != expectedMessage { + return false, fmt.Sprintf( + "Expected commit message to be '%s', but got '%s'", + expectedMessage, headCommit.Name, + ) + } + + return true, "" + }) +} + +func (self *Assert) CurrentViewName(expectedViewName string) { + self.assertWithRetries(func() (bool, string) { + actual := self.gui.CurrentContext().GetView().Name() + return actual == expectedViewName, fmt.Sprintf("Expected current view name to be '%s', but got '%s'", expectedViewName, actual) + }) +} + +func (self *Assert) CurrentBranchName(expectedViewName string) { + 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) + }) +} + +func (self *Assert) InListContext() { + self.assertWithRetries(func() (bool, string) { + currentContext := self.gui.CurrentContext() + _, ok := currentContext.(types.IListContext) + return ok, fmt.Sprintf("Expected current context to be a list context, but got %s", currentContext.GetKey()) + }) +} + +func (self *Assert) SelectedLineContains(text string) { + self.assertWithRetries(func() (bool, string) { + line := self.gui.CurrentContext().GetView().SelectedLine() + return strings.Contains(line, text), fmt.Sprintf("Expected selected line to contain '%s', but got '%s'", text, line) + }) +} + +func (self *Assert) assertWithRetries(test func() (bool, string)) { + waitTimes := []int{0, 1, 5, 10, 200, 500, 1000} + + var message string + for _, waitTime := range waitTimes { + time.Sleep(time.Duration(waitTime) * time.Millisecond) + + var ok bool + ok, message = test() + if ok { + return + } + } + + self.Fail(message) +} + +// for when you just want to fail the test yourself +func (self *Assert) Fail(message string) { + self.gui.Fail(message) +} diff --git a/pkg/integration/components/input.go b/pkg/integration/components/input.go new file mode 100644 index 000000000..bf52e554c --- /dev/null +++ b/pkg/integration/components/input.go @@ -0,0 +1,166 @@ +package components + +import ( + "fmt" + "strings" + "time" + + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/types" + integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" +) + +type Input struct { + gui integrationTypes.GuiAdapter + keys config.KeybindingConfig + assert *Assert + pushKeyDelay int +} + +func NewInput(gui integrationTypes.GuiAdapter, keys config.KeybindingConfig, assert *Assert, pushKeyDelay int) *Input { + return &Input{ + gui: gui, + keys: keys, + assert: assert, + pushKeyDelay: pushKeyDelay, + } +} + +// key is something like 'w' or ''. 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) PressKeys(keyStrs ...string) { + for _, keyStr := range keyStrs { + self.pressKey(keyStr) + } +} + +func (self *Input) pressKey(keyStr string) { + self.Wait(self.pushKeyDelay) + + self.gui.PressKey(keyStr) +} + +func (self *Input) SwitchToStatusWindow() { + self.pressKey(self.keys.Universal.JumpToBlock[0]) +} + +func (self *Input) SwitchToFilesWindow() { + self.pressKey(self.keys.Universal.JumpToBlock[1]) +} + +func (self *Input) SwitchToBranchesWindow() { + self.pressKey(self.keys.Universal.JumpToBlock[2]) +} + +func (self *Input) SwitchToCommitsWindow() { + self.pressKey(self.keys.Universal.JumpToBlock[3]) +} + +func (self *Input) SwitchToStashWindow() { + self.pressKey(self.keys.Universal.JumpToBlock[4]) +} + +func (self *Input) Type(content string) { + for _, char := range content { + self.pressKey(string(char)) + } +} + +// i.e. pressing enter +func (self *Input) Confirm() { + self.pressKey(self.keys.Universal.Confirm) +} + +// i.e. pressing escape +func (self *Input) Cancel() { + self.pressKey(self.keys.Universal.Return) +} + +// i.e. pressing space +func (self *Input) Select() { + self.pressKey(self.keys.Universal.Select) +} + +// i.e. pressing down arrow +func (self *Input) NextItem() { + self.pressKey(self.keys.Universal.NextItem) +} + +// i.e. pressing up arrow +func (self *Input) PreviousItem() { + self.pressKey(self.keys.Universal.PrevItem) +} + +func (self *Input) ContinueMerge() { + self.PressKeys(self.keys.Universal.CreateRebaseOptionsMenu) + self.assert.SelectedLineContains("continue") + self.Confirm() +} + +func (self *Input) ContinueRebase() { + self.ContinueMerge() +} + +// for when you want to allow lazygit to process something before continuing +func (self *Input) Wait(milliseconds int) { + time.Sleep(time.Duration(milliseconds) * time.Millisecond) +} + +func (self *Input) LogUI(message string) { + self.gui.LogUI(message) +} + +func (self *Input) Log(message string) { + self.gui.LogUI(message) +} + +// this will look for a list item in the current panel and if it finds it, it will +// enter the keypresses required to navigate to it. +// The test will fail if: +// - the user is not in a list item +// - no list item is found containing the given text +// - multiple list items are found containing the given text in the initial page of items +// +// NOTE: this currently assumes that ViewBufferLines returns all the lines that can be accessed. +// 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) NavigateToListItemContainingText(text string) { + self.assert.InListContext() + + currentContext := self.gui.CurrentContext().(types.IListContext) + + view := currentContext.GetView() + + // first we look for a duplicate on the current screen. We won't bother looking beyond that though. + matchCount := 0 + matchIndex := -1 + for i, line := range view.ViewBufferLines() { + if strings.Contains(line, text) { + matchCount++ + matchIndex = i + } + } + if matchCount > 1 { + self.assert.Fail(fmt.Sprintf("Found %d matches for %s, expected only a single match", matchCount, text)) + } + if matchCount == 1 { + selectedLineIdx := view.SelectedLineIdx() + if selectedLineIdx == matchIndex { + return + } + if selectedLineIdx < matchIndex { + for i := selectedLineIdx; i < matchIndex; i++ { + self.NextItem() + } + return + } else { + for i := selectedLineIdx; i > matchIndex; i-- { + self.PreviousItem() + } + return + } + } + + self.assert.Fail(fmt.Sprintf("Could not find item containing text: %s", text)) +} diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go new file mode 100644 index 000000000..ee57cf401 --- /dev/null +++ b/pkg/integration/components/shell.go @@ -0,0 +1,83 @@ +package components + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/jesseduffield/lazygit/pkg/secureexec" + "github.com/mgutz/str" +) + +// this is for running shell commands, mostly for the sake of setting up the repo +// but you can also run the commands from within lazygit to emulate things happening +// in the background. +type Shell struct{} + +func NewShell() *Shell { + return &Shell{} +} + +func (s *Shell) RunCommand(cmdStr string) *Shell { + args := str.ToArgv(cmdStr) + cmd := secureexec.Command(args[0], args[1:]...) + cmd.Env = os.Environ() + + output, err := cmd.CombinedOutput() + if err != nil { + panic(fmt.Sprintf("error running command: %s\n%s", cmdStr, string(output))) + } + + return s +} + +func (s *Shell) CreateFile(path string, content string) *Shell { + err := ioutil.WriteFile(path, []byte(content), 0o644) + if err != nil { + panic(fmt.Sprintf("error creating file: %s\n%s", path, err)) + } + + return s +} + +func (s *Shell) NewBranch(name string) *Shell { + return s.RunCommand("git checkout -b " + name) +} + +func (s *Shell) GitAdd(path string) *Shell { + return s.RunCommand(fmt.Sprintf("git add \"%s\"", path)) +} + +func (s *Shell) GitAddAll() *Shell { + return s.RunCommand("git add -A") +} + +func (s *Shell) Commit(message string) *Shell { + return s.RunCommand(fmt.Sprintf("git commit -m \"%s\"", message)) +} + +func (s *Shell) EmptyCommit(message string) *Shell { + return s.RunCommand(fmt.Sprintf("git commit --allow-empty -m \"%s\"", message)) +} + +// convenience method for creating a file and adding it +func (s *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell { + return s. + CreateFile(fileName, fileContents). + GitAdd(fileName) +} + +// creates commits 01, 02, 03, ..., n with a new file in each +// The reason for padding with zeroes is so that it's easier to do string +// matches on the commit messages when there are many of them +func (s *Shell) CreateNCommits(n int) *Shell { + for i := 1; i <= n; i++ { + s.CreateFileAndAdd( + fmt.Sprintf("file%02d.txt", i), + fmt.Sprintf("file%02d content", i), + ). + Commit(fmt.Sprintf("commit %02d", i)) + } + + return s +} diff --git a/pkg/integration/components/test.go b/pkg/integration/components/test.go new file mode 100644 index 000000000..13ffe73f1 --- /dev/null +++ b/pkg/integration/components/test.go @@ -0,0 +1,118 @@ +package components + +import ( + "os" + "strconv" + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// Test describes an integration tests that will be run against the lazygit gui. + +type IntegrationTest struct { + name string + description string + extraCmdArgs string + skip bool + setupRepo func(shell *Shell) + setupConfig func(config *config.AppConfig) + run func( + shell *Shell, + input *Input, + assert *Assert, + keys config.KeybindingConfig, + ) +} + +var _ integrationTypes.IntegrationTest = &IntegrationTest{} + +type NewIntegrationTestArgs struct { + // Briefly describes what happens in the test and what it's testing for + Description string + // prepares a repo for testing + SetupRepo func(shell *Shell) + // takes a config and mutates. The mutated context will end up being passed to the gui + SetupConfig func(config *config.AppConfig) + // runs the test + Run func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) + // additional args passed to lazygit + ExtraCmdArgs string + // for when a test is flakey + Skip bool +} + +func NewIntegrationTest(args NewIntegrationTestArgs) *IntegrationTest { + return &IntegrationTest{ + name: testNameFromFilePath(), + description: args.Description, + extraCmdArgs: args.ExtraCmdArgs, + skip: args.Skip, + setupRepo: args.SetupRepo, + setupConfig: args.SetupConfig, + run: args.Run, + } +} + +func (self *IntegrationTest) Name() string { + return self.name +} + +func (self *IntegrationTest) Description() string { + return self.description +} + +func (self *IntegrationTest) ExtraCmdArgs() string { + return self.extraCmdArgs +} + +func (self *IntegrationTest) Skip() bool { + return self.skip +} + +func (self *IntegrationTest) SetupConfig(config *config.AppConfig) { + self.setupConfig(config) +} + +func (self *IntegrationTest) SetupRepo(shell *Shell) { + self.setupRepo(shell) +} + +// I want access to all contexts, the model, the ability to press a key, the ability to log, +func (self *IntegrationTest) Run(gui integrationTypes.GuiAdapter) { + shell := NewShell() + assert := NewAssert(gui) + keys := gui.Keys() + input := NewInput(gui, keys, assert, KeyPressDelay()) + + self.run(shell, input, assert, keys) + + if KeyPressDelay() > 0 { + // the dev would want to see the final state if they're running in slow mode + input.Wait(2000) + } +} + +func testNameFromFilePath() string { + path := utils.FilePath(3) + name := strings.Split(path, "integration/tests/")[1] + + return name[:len(name)-len(".go")] +} + +// this is the delay in milliseconds between keypresses +// defaults to zero +func KeyPressDelay() int { + delayStr := os.Getenv("KEY_PRESS_DELAY") + if delayStr == "" { + return 0 + } + + delay, err := strconv.Atoi(delayStr) + if err != nil { + panic(err) + } + return delay +} diff --git a/pkg/integration/helpers/assert.go b/pkg/integration/helpers/assert.go deleted file mode 100644 index 41b280bcb..000000000 --- a/pkg/integration/helpers/assert.go +++ /dev/null @@ -1,111 +0,0 @@ -package helpers - -import ( - "fmt" - "strings" - "time" - - "github.com/jesseduffield/lazygit/pkg/gui/types" - integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" -) - -// through this struct we assert on the state of the lazygit gui - -type Assert struct { - gui integrationTypes.GuiAdapter -} - -func NewAssert(gui integrationTypes.GuiAdapter) *Assert { - return &Assert{gui: gui} -} - -func (self *Assert) WorkingTreeFileCount(expectedCount int) { - self.assertWithRetries(func() (bool, string) { - actualCount := len(self.gui.Model().Files) - - return actualCount == expectedCount, fmt.Sprintf( - "Expected %d changed working tree files, but got %d", - expectedCount, actualCount, - ) - }) -} - -func (self *Assert) CommitCount(expectedCount int) { - self.assertWithRetries(func() (bool, string) { - actualCount := len(self.gui.Model().Commits) - - return actualCount == expectedCount, fmt.Sprintf( - "Expected %d commits present, but got %d", - expectedCount, actualCount, - ) - }) -} - -func (self *Assert) HeadCommitMessage(expectedMessage string) { - self.assertWithRetries(func() (bool, string) { - if len(self.gui.Model().Commits) == 0 { - return false, "Expected at least one commit to be present" - } - - headCommit := self.gui.Model().Commits[0] - if headCommit.Name != expectedMessage { - return false, fmt.Sprintf( - "Expected commit message to be '%s', but got '%s'", - expectedMessage, headCommit.Name, - ) - } - - return true, "" - }) -} - -func (self *Assert) CurrentViewName(expectedViewName string) { - self.assertWithRetries(func() (bool, string) { - actual := self.gui.CurrentContext().GetView().Name() - return actual == expectedViewName, fmt.Sprintf("Expected current view name to be '%s', but got '%s'", expectedViewName, actual) - }) -} - -func (self *Assert) CurrentBranchName(expectedViewName string) { - 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) - }) -} - -func (self *Assert) InListContext() { - self.assertWithRetries(func() (bool, string) { - currentContext := self.gui.CurrentContext() - _, ok := currentContext.(types.IListContext) - return ok, fmt.Sprintf("Expected current context to be a list context, but got %s", currentContext.GetKey()) - }) -} - -func (self *Assert) SelectedLineContains(text string) { - self.assertWithRetries(func() (bool, string) { - line := self.gui.CurrentContext().GetView().SelectedLine() - return strings.Contains(line, text), fmt.Sprintf("Expected selected line to contain '%s', but got '%s'", text, line) - }) -} - -func (self *Assert) assertWithRetries(test func() (bool, string)) { - waitTimes := []int{0, 1, 5, 10, 200, 500, 1000} - - var message string - for _, waitTime := range waitTimes { - time.Sleep(time.Duration(waitTime) * time.Millisecond) - - var ok bool - ok, message = test() - if ok { - return - } - } - - self.Fail(message) -} - -// for when you just want to fail the test yourself -func (self *Assert) Fail(message string) { - self.gui.Fail(message) -} diff --git a/pkg/integration/helpers/input.go b/pkg/integration/helpers/input.go deleted file mode 100644 index 55e1f8527..000000000 --- a/pkg/integration/helpers/input.go +++ /dev/null @@ -1,166 +0,0 @@ -package helpers - -import ( - "fmt" - "strings" - "time" - - "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/gui/types" - integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" -) - -type Input struct { - gui integrationTypes.GuiAdapter - keys config.KeybindingConfig - assert *Assert - pushKeyDelay int -} - -func NewInput(gui integrationTypes.GuiAdapter, keys config.KeybindingConfig, assert *Assert, pushKeyDelay int) *Input { - return &Input{ - gui: gui, - keys: keys, - assert: assert, - pushKeyDelay: pushKeyDelay, - } -} - -// key is something like 'w' or ''. 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) PressKeys(keyStrs ...string) { - for _, keyStr := range keyStrs { - self.pressKey(keyStr) - } -} - -func (self *Input) pressKey(keyStr string) { - self.Wait(self.pushKeyDelay) - - self.gui.PressKey(keyStr) -} - -func (self *Input) SwitchToStatusWindow() { - self.pressKey(self.keys.Universal.JumpToBlock[0]) -} - -func (self *Input) SwitchToFilesWindow() { - self.pressKey(self.keys.Universal.JumpToBlock[1]) -} - -func (self *Input) SwitchToBranchesWindow() { - self.pressKey(self.keys.Universal.JumpToBlock[2]) -} - -func (self *Input) SwitchToCommitsWindow() { - self.pressKey(self.keys.Universal.JumpToBlock[3]) -} - -func (self *Input) SwitchToStashWindow() { - self.pressKey(self.keys.Universal.JumpToBlock[4]) -} - -func (self *Input) Type(content string) { - for _, char := range content { - self.pressKey(string(char)) - } -} - -// i.e. pressing enter -func (self *Input) Confirm() { - self.pressKey(self.keys.Universal.Confirm) -} - -// i.e. pressing escape -func (self *Input) Cancel() { - self.pressKey(self.keys.Universal.Return) -} - -// i.e. pressing space -func (self *Input) Select() { - self.pressKey(self.keys.Universal.Select) -} - -// i.e. pressing down arrow -func (self *Input) NextItem() { - self.pressKey(self.keys.Universal.NextItem) -} - -// i.e. pressing up arrow -func (self *Input) PreviousItem() { - self.pressKey(self.keys.Universal.PrevItem) -} - -func (self *Input) ContinueMerge() { - self.PressKeys(self.keys.Universal.CreateRebaseOptionsMenu) - self.assert.SelectedLineContains("continue") - self.Confirm() -} - -func (self *Input) ContinueRebase() { - self.ContinueMerge() -} - -// for when you want to allow lazygit to process something before continuing -func (self *Input) Wait(milliseconds int) { - time.Sleep(time.Duration(milliseconds) * time.Millisecond) -} - -func (self *Input) LogUI(message string) { - self.gui.LogUI(message) -} - -func (self *Input) Log(message string) { - self.gui.LogUI(message) -} - -// this will look for a list item in the current panel and if it finds it, it will -// enter the keypresses required to navigate to it. -// The test will fail if: -// - the user is not in a list item -// - no list item is found containing the given text -// - multiple list items are found containing the given text in the initial page of items -// -// NOTE: this currently assumes that ViewBufferLines returns all the lines that can be accessed. -// 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) NavigateToListItemContainingText(text string) { - self.assert.InListContext() - - currentContext := self.gui.CurrentContext().(types.IListContext) - - view := currentContext.GetView() - - // first we look for a duplicate on the current screen. We won't bother looking beyond that though. - matchCount := 0 - matchIndex := -1 - for i, line := range view.ViewBufferLines() { - if strings.Contains(line, text) { - matchCount++ - matchIndex = i - } - } - if matchCount > 1 { - self.assert.Fail(fmt.Sprintf("Found %d matches for %s, expected only a single match", matchCount, text)) - } - if matchCount == 1 { - selectedLineIdx := view.SelectedLineIdx() - if selectedLineIdx == matchIndex { - return - } - if selectedLineIdx < matchIndex { - for i := selectedLineIdx; i < matchIndex; i++ { - self.NextItem() - } - return - } else { - for i := selectedLineIdx; i > matchIndex; i-- { - self.PreviousItem() - } - return - } - } - - self.assert.Fail(fmt.Sprintf("Could not find item containing text: %s", text)) -} diff --git a/pkg/integration/helpers/shell.go b/pkg/integration/helpers/shell.go deleted file mode 100644 index b70a8ffaa..000000000 --- a/pkg/integration/helpers/shell.go +++ /dev/null @@ -1,83 +0,0 @@ -package helpers - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/jesseduffield/lazygit/pkg/secureexec" - "github.com/mgutz/str" -) - -// this is for running shell commands, mostly for the sake of setting up the repo -// but you can also run the commands from within lazygit to emulate things happening -// in the background. -type Shell struct{} - -func NewShell() *Shell { - return &Shell{} -} - -func (s *Shell) RunCommand(cmdStr string) *Shell { - args := str.ToArgv(cmdStr) - cmd := secureexec.Command(args[0], args[1:]...) - cmd.Env = os.Environ() - - output, err := cmd.CombinedOutput() - if err != nil { - panic(fmt.Sprintf("error running command: %s\n%s", cmdStr, string(output))) - } - - return s -} - -func (s *Shell) CreateFile(path string, content string) *Shell { - err := ioutil.WriteFile(path, []byte(content), 0o644) - if err != nil { - panic(fmt.Sprintf("error creating file: %s\n%s", path, err)) - } - - return s -} - -func (s *Shell) NewBranch(name string) *Shell { - return s.RunCommand("git checkout -b " + name) -} - -func (s *Shell) GitAdd(path string) *Shell { - return s.RunCommand(fmt.Sprintf("git add \"%s\"", path)) -} - -func (s *Shell) GitAddAll() *Shell { - return s.RunCommand("git add -A") -} - -func (s *Shell) Commit(message string) *Shell { - return s.RunCommand(fmt.Sprintf("git commit -m \"%s\"", message)) -} - -func (s *Shell) EmptyCommit(message string) *Shell { - return s.RunCommand(fmt.Sprintf("git commit --allow-empty -m \"%s\"", message)) -} - -// convenience method for creating a file and adding it -func (s *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell { - return s. - CreateFile(fileName, fileContents). - GitAdd(fileName) -} - -// creates commits 01, 02, 03, ..., n with a new file in each -// The reason for padding with zeroes is so that it's easier to do string -// matches on the commit messages when there are many of them -func (s *Shell) CreateNCommits(n int) *Shell { - for i := 1; i <= n; i++ { - s.CreateFileAndAdd( - fmt.Sprintf("file%02d.txt", i), - fmt.Sprintf("file%02d content", i), - ). - Commit(fmt.Sprintf("commit %02d", i)) - } - - return s -} diff --git a/pkg/integration/helpers/test.go b/pkg/integration/helpers/test.go deleted file mode 100644 index fb876be7f..000000000 --- a/pkg/integration/helpers/test.go +++ /dev/null @@ -1,118 +0,0 @@ -package helpers - -import ( - "os" - "strconv" - "strings" - - "github.com/jesseduffield/lazygit/pkg/config" - integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -// Test describes an integration tests that will be run against the lazygit gui. - -type IntegrationTest struct { - name string - description string - extraCmdArgs string - skip bool - setupRepo func(shell *Shell) - setupConfig func(config *config.AppConfig) - run func( - shell *Shell, - input *Input, - assert *Assert, - keys config.KeybindingConfig, - ) -} - -var _ integrationTypes.IntegrationTest = &IntegrationTest{} - -type NewIntegrationTestArgs struct { - // Briefly describes what happens in the test and what it's testing for - Description string - // prepares a repo for testing - SetupRepo func(shell *Shell) - // takes a config and mutates. The mutated context will end up being passed to the gui - SetupConfig func(config *config.AppConfig) - // runs the test - Run func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) - // additional args passed to lazygit - ExtraCmdArgs string - // for when a test is flakey - Skip bool -} - -func NewIntegrationTest(args NewIntegrationTestArgs) *IntegrationTest { - return &IntegrationTest{ - name: testNameFromFilePath(), - description: args.Description, - extraCmdArgs: args.ExtraCmdArgs, - skip: args.Skip, - setupRepo: args.SetupRepo, - setupConfig: args.SetupConfig, - run: args.Run, - } -} - -func (self *IntegrationTest) Name() string { - return self.name -} - -func (self *IntegrationTest) Description() string { - return self.description -} - -func (self *IntegrationTest) ExtraCmdArgs() string { - return self.extraCmdArgs -} - -func (self *IntegrationTest) Skip() bool { - return self.skip -} - -func (self *IntegrationTest) SetupConfig(config *config.AppConfig) { - self.setupConfig(config) -} - -func (self *IntegrationTest) SetupRepo(shell *Shell) { - self.setupRepo(shell) -} - -// I want access to all contexts, the model, the ability to press a key, the ability to log, -func (self *IntegrationTest) Run(gui integrationTypes.GuiAdapter) { - shell := NewShell() - assert := NewAssert(gui) - keys := gui.Keys() - input := NewInput(gui, keys, assert, KeyPressDelay()) - - self.run(shell, input, assert, keys) - - if KeyPressDelay() > 0 { - // the dev would want to see the final state if they're running in slow mode - input.Wait(2000) - } -} - -func testNameFromFilePath() string { - path := utils.FilePath(3) - name := strings.Split(path, "integration/tests/")[1] - - return name[:len(name)-len(".go")] -} - -// this is the delay in milliseconds between keypresses -// defaults to zero -func KeyPressDelay() int { - delayStr := os.Getenv("KEY_PRESS_DELAY") - if delayStr == "" { - return 0 - } - - delay, err := strconv.Atoi(delayStr) - if err != nil { - panic(err) - } - return delay -} diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index 6227649e6..c50594054 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -12,7 +12,7 @@ import ( "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" "github.com/jesseduffield/lazygit/pkg/integration/tests" "github.com/stretchr/testify/assert" ) @@ -45,7 +45,7 @@ type ( func RunTests( logf logf, runCmd func(cmd *exec.Cmd) error, - fnWrapper func(test *helpers.IntegrationTest, f func() error), + fnWrapper func(test *components.IntegrationTest, f func() error), mode Mode, includeSkipped bool, ) error { @@ -229,12 +229,12 @@ func compareSnapshots(logf logf, configDir string, actualDir string, expectedDir return nil } -func createFixture(test *helpers.IntegrationTest, actualDir string, rootDir string) error { +func createFixture(test *components.IntegrationTest, actualDir string, rootDir string) error { if err := os.Chdir(actualDir); err != nil { panic(err) } - shell := helpers.NewShell() + shell := components.NewShell() shell.RunCommand("git init") shell.RunCommand(`git config user.email "CI@example.com"`) shell.RunCommand(`git config user.name "CI"`) @@ -249,7 +249,7 @@ func createFixture(test *helpers.IntegrationTest, actualDir string, rootDir stri return nil } -func getLazygitCommand(test *helpers.IntegrationTest, testPath string, rootDir string) (*exec.Cmd, error) { +func getLazygitCommand(test *components.IntegrationTest, testPath string, rootDir string) (*exec.Cmd, error) { osCommand := oscommands.NewDummyOSCommand() templateConfigDir := filepath.Join(rootDir, "test", "default_test_config") diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go index 2c59b94df..3637b0a70 100644 --- a/pkg/integration/integration_test.go +++ b/pkg/integration/integration_test.go @@ -15,7 +15,6 @@ import ( "testing" "github.com/creack/pty" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" "github.com/stretchr/testify/assert" ) @@ -34,7 +33,7 @@ func TestIntegration(t *testing.T) { err := RunTests( t.Logf, runCmdHeadless, - func(test *helpers.IntegrationTest, f func() error) { + func(test *components.IntegrationTest, f func() error) { defer func() { testNumber += 1 }() if testNumber%parallelTotal != parallelIndex { return diff --git a/pkg/integration/runner/main.go b/pkg/integration/runner/main.go index 820df712a..25c0acf8f 100644 --- a/pkg/integration/runner/main.go +++ b/pkg/integration/runner/main.go @@ -7,7 +7,6 @@ import ( "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/integration" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" ) // see pkg/integration/README.md @@ -17,7 +16,7 @@ import ( func main() { mode := integration.GetModeFromEnv() includeSkipped := os.Getenv("INCLUDE_SKIPPED") == "true" - var testsToRun []*helpers.IntegrationTest + var testsToRun []*components.IntegrationTest if len(os.Args) > 1 { outer: @@ -35,14 +34,14 @@ func main() { testsToRun = integration.Tests } - testNames := slices.Map(testsToRun, func(test *helpers.IntegrationTest) string { + testNames := slices.Map(testsToRun, func(test *components.IntegrationTest) string { return test.Name() }) err := integration.RunTests( log.Printf, runCmdInTerminal, - func(test *helpers.IntegrationTest, f func() error) { + func(test *components.IntegrationTest, f func() error) { if !slices.Contains(testNames, test.Name()) { return } diff --git a/pkg/integration/tests/branch/suggestions.go b/pkg/integration/tests/branch/suggestions.go index 33d0cf316..2bd4fa340 100644 --- a/pkg/integration/tests/branch/suggestions.go +++ b/pkg/integration/tests/branch/suggestions.go @@ -2,15 +2,15 @@ package branch import ( "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var Suggestions = helpers.NewIntegrationTest(helpers.NewIntegrationTestArgs{ +var Suggestions = components.NewIntegrationTest(components.NewIntegrationTestArgs{ Description: "Checking out a branch with name suggestions", ExtraCmdArgs: "", Skip: false, SetupConfig: func(config *config.AppConfig) {}, - SetupRepo: func(shell *helpers.Shell) { + SetupRepo: func(shell *components.Shell) { shell. EmptyCommit("my commit message"). NewBranch("new-branch"). @@ -20,7 +20,7 @@ var Suggestions = helpers.NewIntegrationTest(helpers.NewIntegrationTestArgs{ NewBranch("other-new-branch-2"). NewBranch("other-new-branch-3") }, - Run: func(shell *helpers.Shell, input *helpers.Input, assert *helpers.Assert, keys config.KeybindingConfig) { + Run: func(shell *components.Shell, input *components.Input, assert *components.Assert, keys config.KeybindingConfig) { input.SwitchToBranchesWindow() input.PressKeys(keys.Branches.CheckoutBranchByName) diff --git a/pkg/integration/tests/commit/commit.go b/pkg/integration/tests/commit/commit.go index bbdcf5278..12a68925d 100644 --- a/pkg/integration/tests/commit/commit.go +++ b/pkg/integration/tests/commit/commit.go @@ -2,19 +2,19 @@ package commit import ( "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var Commit = helpers.NewIntegrationTest(helpers.NewIntegrationTestArgs{ +var Commit = components.NewIntegrationTest(components.NewIntegrationTestArgs{ Description: "Staging a couple files and committing", ExtraCmdArgs: "", Skip: false, SetupConfig: func(config *config.AppConfig) {}, - SetupRepo: func(shell *helpers.Shell) { + SetupRepo: func(shell *components.Shell) { shell.CreateFile("myfile", "myfile content") shell.CreateFile("myfile2", "myfile2 content") }, - Run: func(shell *helpers.Shell, input *helpers.Input, assert *helpers.Assert, keys config.KeybindingConfig) { + Run: func(shell *components.Shell, input *components.Input, assert *components.Assert, keys config.KeybindingConfig) { assert.CommitCount(0) input.Select() diff --git a/pkg/integration/tests/commit/new_branch.go b/pkg/integration/tests/commit/new_branch.go index 419da6890..ad96938f5 100644 --- a/pkg/integration/tests/commit/new_branch.go +++ b/pkg/integration/tests/commit/new_branch.go @@ -2,21 +2,21 @@ package commit import ( "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var NewBranch = helpers.NewIntegrationTest(helpers.NewIntegrationTestArgs{ +var NewBranch = components.NewIntegrationTest(components.NewIntegrationTestArgs{ Description: "Creating a new branch from a commit", ExtraCmdArgs: "", Skip: false, SetupConfig: func(config *config.AppConfig) {}, - SetupRepo: func(shell *helpers.Shell) { + SetupRepo: func(shell *components.Shell) { shell. EmptyCommit("commit 1"). EmptyCommit("commit 2"). EmptyCommit("commit 3") }, - Run: func(shell *helpers.Shell, input *helpers.Input, assert *helpers.Assert, keys config.KeybindingConfig) { + Run: func(shell *components.Shell, input *components.Input, assert *components.Assert, keys config.KeybindingConfig) { assert.CommitCount(3) input.SwitchToCommitsWindow() diff --git a/pkg/integration/tests/interactive_rebase/one.go b/pkg/integration/tests/interactive_rebase/one.go index 69332c7de..3c785a727 100644 --- a/pkg/integration/tests/interactive_rebase/one.go +++ b/pkg/integration/tests/interactive_rebase/one.go @@ -2,19 +2,19 @@ package interactive_rebase import ( "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var One = helpers.NewIntegrationTest(helpers.NewIntegrationTestArgs{ +var One = components.NewIntegrationTest(components.NewIntegrationTestArgs{ Description: "Begins an interactive rebase, then fixups, drops, and squashes some commits", ExtraCmdArgs: "", Skip: false, SetupConfig: func(config *config.AppConfig) {}, - SetupRepo: func(shell *helpers.Shell) { + SetupRepo: func(shell *components.Shell) { shell. CreateNCommits(5) // these will appears at commit 05, 04, 04, down to 01 }, - Run: func(shell *helpers.Shell, input *helpers.Input, assert *helpers.Assert, keys config.KeybindingConfig) { + Run: func(shell *components.Shell, input *components.Input, assert *components.Assert, keys config.KeybindingConfig) { input.SwitchToCommitsWindow() assert.CurrentViewName("commits") diff --git a/pkg/integration/tests/tests.go b/pkg/integration/tests/tests.go index dbd44470d..e9794169a 100644 --- a/pkg/integration/tests/tests.go +++ b/pkg/integration/tests/tests.go @@ -1,7 +1,7 @@ package tests import ( - "github.com/jesseduffield/lazygit/pkg/integration/helpers" + "github.com/jesseduffield/lazygit/pkg/integration/components" "github.com/jesseduffield/lazygit/pkg/integration/tests/branch" "github.com/jesseduffield/lazygit/pkg/integration/tests/commit" "github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase" @@ -10,7 +10,7 @@ import ( // Here is where we lists the actual tests that will run. When you create a new test, // be sure to add it to this list. -var Tests = []*helpers.IntegrationTest{ +var Tests = []*components.IntegrationTest{ commit.Commit, commit.NewBranch, branch.Suggestions, diff --git a/pkg/integration/tui/main.go b/pkg/integration/tui/main.go index 8b00c4951..97aa90c2e 100644 --- a/pkg/integration/tui/main.go +++ b/pkg/integration/tui/main.go @@ -11,21 +11,20 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/integration" - "github.com/jesseduffield/lazygit/pkg/integration/helpers" "github.com/jesseduffield/lazygit/pkg/secureexec" ) // this program lets you manage integration tests in a TUI. See pkg/integration/README.md for more info. type App struct { - tests []*helpers.IntegrationTest + tests []*components.IntegrationTest itemIdx int testDir string filtering bool g *gocui.Gui } -func (app *App) getCurrentTest() *helpers.IntegrationTest { +func (app *App) getCurrentTest() *components.IntegrationTest { if len(app.tests) > 0 { return app.tests[app.itemIdx] } -- cgit v1.2.3