diff options
70 files changed, 322 insertions, 272 deletions
diff --git a/.gitignore b/.gitignore index 57f63c955..09b2235f1 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ lazygit.exe test/git_server/data -test/integration/** +test/results/** oryxBuildBinary __debug_bin diff --git a/pkg/commands/hosting_service/hosting_service_test.go b/pkg/commands/hosting_service/hosting_service_test.go index ded310c85..d67d94ed8 100644 --- a/pkg/commands/hosting_service/hosting_service_test.go +++ b/pkg/commands/hosting_service/hosting_service_test.go @@ -3,8 +3,8 @@ package hosting_service import ( "testing" + "github.com/jesseduffield/lazygit/pkg/fakes" "github.com/jesseduffield/lazygit/pkg/i18n" - "github.com/jesseduffield/lazygit/pkg/test" "github.com/stretchr/testify/assert" ) @@ -328,7 +328,7 @@ func TestGetPullRequestURL(t *testing.T) { s := s t.Run(s.testName, func(t *testing.T) { tr := i18n.EnglishTranslationSet() - log := &test.FakeFieldLogger{} + log := &fakes.FakeFieldLogger{} hostingServiceMgr := NewHostingServiceMgr(log, &tr, s.remoteUrl, s.configServiceDomains) s.test(hostingServiceMgr.GetPullRequestURL(s.from, s.to)) log.AssertErrors(t, s.expectedLoggedErrors) diff --git a/pkg/test/log.go b/pkg/fakes/log.go index 32d79b987..fc68f23c1 100644 --- a/pkg/test/log.go +++ b/pkg/fakes/log.go @@ -1,4 +1,4 @@ -package test +package fakes import ( "fmt" diff --git a/pkg/integration/README.md b/pkg/integration/README.md index 598810a82..6dfadd8f8 100644 --- a/pkg/integration/README.md +++ b/pkg/integration/README.md @@ -16,7 +16,7 @@ go run cmd/integration_test/main.go cli [--slow or --sandbox] [testname or testp ## Writing tests -The tests live in pkg/integration/tests. Each test is listed in `pkg/integration/tests/tests_gen.go` which is an auto-generated file. You can re-generate that file by running `go generate ./...` at the root of the Lazygit repo. +The tests live in pkg/integration/tests. Each test is registered in `pkg/integration/tests/test_list.go` which is an auto-generated file. You can re-generate that file by running `go generate ./...` at the root of the Lazygit repo. Each test has two important steps: the setup step and the run step. @@ -34,18 +34,6 @@ The run step has two arguments passed in: `t` is for driving the gui by pressing certain keys, selecting list items, etc. `keys` is for use when getting the test to press a particular key e.g. `t.Views().Commits().Focus().PressKey(keys.Universal.Confirm)` -### Tips - -#### Handle most setup in the `shell` part of the test - -Try to do as much setup work as possible in your setup step. For example, if all you're testing is that the user is able to resolve merge conflicts, create the merge conflicts in the setup step. On the other hand, if you're testing to see that lazygit can warn the user about merge conflicts after an attempted merge, it's fine to wait until the run step to actually create the conflicts. If the run step is focused on the thing you're trying to test, the test will run faster and its intent will be clearer. - -#### Create helper functions for (very) frequently used test logic - -If you find yourself doing something frequently in a test, consider making it a method in one of the helper arguments. For example, instead of calling `t.PressKey(keys.Universal.Confirm)` in 100 places, it's better to have a method `t.Confirm()`. This is not to say that everything should be made into a helper method: just things that are particularly common in tests. - -Also, given how often we need to select a menu item or type into a prompt panel, there are some helper functions for that. See `ExpectConfirmation` for an example. - ## Running tests There are three ways to invoke a test: @@ -62,7 +50,7 @@ The name of a test is based on its path, so the name of the test at `pkg/integra You can pass the KEY_PRESS_DELAY env var to the test runner in order to set a delay in milliseconds between keypresses, which helps for watching a test at a realistic speed to understand what it's doing. Or you can pass the '--slow' flag which sets a pre-set 'slow' key delay. In the tui you can press 't' to run the test in slow mode. -The resultant repo will be stored in `test/integration`, so if you're not sure what went wrong you can go there and inspect the repo. +The resultant repo will be stored in `test/results`, so if you're not sure what went wrong you can go there and inspect the repo. ### Running tests in VSCode @@ -78,3 +66,19 @@ The test will run in a VSCode terminal: Say you want to do a manual test of how lazygit handles merge-conflicts, but you can't be bothered actually finding a way to create merge conflicts in a repo. To make your life easier, you can simply run a merge-conflicts test in sandbox mode, meaning the setup step is run for you, and then instead of the test driving the lazygit session, you're allowed to drive it yourself. To run a test in sandbox mode you can press 's' on a test in the test TUI or in the test runner pass the --sandbox argument. + +## Tips for writing tests + +### Handle most setup in the `shell` part of the test + +Try to do as much setup work as possible in your setup step. For example, if all you're testing is that the user is able to resolve merge conflicts, create the merge conflicts in the setup step. On the other hand, if you're testing to see that lazygit can warn the user about merge conflicts after an attempted merge, it's fine to wait until the run step to actually create the conflicts. If the run step is focused on the thing you're trying to test, the test will run faster and its intent will be clearer. + +### Create helper functions for (very) frequently used test logic + +If within a test directory you find several tests need to share some logic, you can create a file called `shared.go` in that directory to hold shared helper functions (see `pkg/integration/tests/filter_by_path/shared.go` for an example). + +If you need to share test logic across test directories you can put helper functions in the `tests/shared` package. If you find yourself frequently doing the same thing from within a test across test directories, for example, responding a particular popup, consider adding a helper method to `pkg/integration/components/common.go`. If you look around the code in the `components` directory you may find another place that's sensible to put your helper function. + +### Don't do too much in one test + +If you're testing different pieces of functionality, it's better to test them in isolation using multiple short tests, compared to one larger longer test. Sometimes it's appropriate to have a longer test which tests how various different pieces interact, but err on the side of keeping things short. diff --git a/pkg/integration/clients/cli.go b/pkg/integration/clients/cli.go index 1030d7690..8ac9947e9 100644 --- a/pkg/integration/clients/cli.go +++ b/pkg/integration/clients/cli.go @@ -11,6 +11,7 @@ import ( "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/integration/components" "github.com/jesseduffield/lazygit/pkg/integration/tests" + "github.com/samber/lo" ) // see pkg/integration/README.md @@ -65,6 +66,12 @@ func getTestsToRun(testNames []string) []*components.IntegrationTest { ) }) + if lo.SomeBy(testNames, func(name string) bool { + return strings.HasSuffix(name, "/shared") + }) { + log.Fatalf("'shared' is a reserved name for tests that are shared between multiple test files. Please rename your test.") + } + outer: for _, testName := range testNames { // check if our given test name actually exists @@ -74,7 +81,7 @@ outer: continue outer } } - log.Fatalf("test %s not found. Perhaps you forgot to add it to `pkg/integration/integration_tests/tests_gen.go`? This can be done by running `go generate ./...` from the Lazygit root. You'll need to ensure that your test name and the file name match (where the test name is in PascalCase and the file name is in snake_case).", testName) + log.Fatalf("test %s not found. Perhaps you forgot to add it to `pkg/integration/integration_tests/test_list.go`? This can be done by running `go generate ./...` from the Lazygit root. You'll need to ensure that your test name and the file name match (where the test name is in PascalCase and the file name is in snake_case).", testName) } return testsToRun diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index 10bfcf748..f93f4589a 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -137,7 +137,7 @@ func RunTUI() { return nil } - cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code test/integration/%s", currentTest.Name())) + cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code test/results/%s", currentTest.Name())) if err := cmd.Run(); err != nil { return err } diff --git a/pkg/integration/components/assertion_helper.go b/pkg/integration/components/assertion_helper.go index b60bda17b..4ae785db2 100644 --- a/pkg/integration/components/assertion_helper.go +++ b/pkg/integration/components/assertion_helper.go @@ -18,7 +18,7 @@ func retryWaitTimes() []int { // give it more leeway compared to when we're running things locally. return []int{0, 1, 1, 1, 1, 1, 5, 10, 20, 40, 100, 200, 500, 1000, 2000, 4000} } else { - return []int{0, 1, 1, 1, 1, 1, 5, 10, 20, 40, 100} + return []int{0, 1, 1, 1, 1, 1, 5, 10, 20, 40, 100, 200} } } diff --git a/pkg/integration/components/actions.go b/pkg/integration/components/common.go index 5e37fc966..7be48e4bd 100644 --- a/pkg/integration/components/actions.go +++ b/pkg/integration/components/common.go @@ -1,12 +1,12 @@ package components // for running common actions -type Actions struct { +type Common struct { t *TestDriver } -func (self *Actions) ContinueMerge() { - self.t.Views().current().Press(self.t.keys.Universal.CreateRebaseOptionsMenu) +func (self *Common) ContinueMerge() { + self.t.GlobalPress(self.t.keys.Universal.CreateRebaseOptionsMenu) self.t.ExpectPopup().Menu(). Title(Equals("Rebase Options")). @@ -14,32 +14,32 @@ func (self *Actions) ContinueMerge() { Confirm() } -func (self *Actions) ContinueRebase() { +func (self *Common) ContinueRebase() { self.ContinueMerge() } -func (self *Actions) AcknowledgeConflicts() { +func (self *Common) AcknowledgeConflicts() { self.t.ExpectPopup().Confirmation(). Title(Equals("Auto-merge failed")). Content(Contains("Conflicts!")). Confirm() } -func (self *Actions) ContinueOnConflictsResolved() { +func (self *Common) ContinueOnConflictsResolved() { self.t.ExpectPopup().Confirmation(). Title(Equals("continue")). Content(Contains("all merge conflicts resolved. Continue?")). Confirm() } -func (self *Actions) ConfirmDiscardLines() { +func (self *Common) ConfirmDiscardLines() { self.t.ExpectPopup().Confirmation(). Title(Equals("Unstage lines")). Content(Contains("Are you sure you want to delete the selected lines")). Confirm() } -func (self *Actions) SelectPatchOption(matcher *Matcher) { +func (self *Common) SelectPatchOption(matcher *Matcher) { self.t.GlobalPress(self.t.keys.Universal.CreatePatchOptionsMenu) self.t.ExpectPopup().Menu().Title(Equals("Patch Options")).Select(matcher).Confirm() diff --git a/pkg/integration/components/menu_driver.go b/pkg/integration/components/menu_driver.go index 326435f52..4092879da 100644 --- a/pkg/integration/components/menu_driver.go +++ b/pkg/integration/components/menu_driver.go @@ -31,7 +31,7 @@ func (self *MenuDriver) Cancel() { } func (self *MenuDriver) Select(option *Matcher) *MenuDriver { - self.getViewDriver().NavigateToListItem(option) + self.getViewDriver().NavigateToLine(option) return self } diff --git a/pkg/integration/components/paths.go b/pkg/integration/components/paths.go index 43468f509..bacc96f81 100644 --- a/pkg/integration/components/paths.go +++ b/pkg/integration/components/paths.go @@ -3,9 +3,9 @@ package components import "path/filepath" // convenience struct for easily getting directories within our test directory. -// We have one test directory for each test, found in test/integration. +// We have one test directory for each test, found in test/results. type Paths struct { - // e.g. test/integration/test_name + // e.g. test/results/test_name root string } diff --git a/pkg/integration/components/prompt_driver.go b/pkg/integration/components/prompt_driver.go index 58051bc70..d21d6f95e 100644 --- a/pkg/integration/components/prompt_driver.go +++ b/pkg/integration/components/prompt_driver.go @@ -79,6 +79,6 @@ func (self *PromptDriver) ConfirmSuggestion(matcher *Matcher) { self.t.press(self.t.keys.Universal.TogglePanel) self.t.Views().Suggestions(). IsFocused(). - NavigateToListItem(matcher). + NavigateToLine(matcher). PressEnter() } diff --git a/pkg/integration/components/runner.go b/pkg/integration/components/runner.go index 394ac00df..43e4f9304 100644 --- a/pkg/integration/components/runner.go +++ b/pkg/integration/components/runner.go @@ -11,14 +11,16 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" ) -// this is the integration runner for the new and improved integration interface - const ( TEST_NAME_ENV_VAR = "TEST_NAME" SANDBOX_ENV_VAR = "SANDBOX" GIT_CONFIG_GLOBAL_ENV_VAR = "GIT_CONFIG_GLOBAL" ) +// This function lets you run tests either from within `go test` or from a regular binary. +// The reason for having two separate ways of testing is that `go test` isn't great at +// showing |