mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-04 10:34:55 +02:00
Merge pull request #2329 from jesseduffield/yet-more-test-migrations
This commit is contained in:
commit
05425cfba0
21
.vscode/tasks.json
vendored
21
.vscode/tasks.json
vendored
@ -29,6 +29,9 @@
|
|||||||
"group": {
|
"group": {
|
||||||
"kind": "test",
|
"kind": "test",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"focus": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -38,6 +41,9 @@
|
|||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "test",
|
"kind": "test",
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"focus": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -47,6 +53,21 @@
|
|||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "test",
|
"kind": "test",
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"focus": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Open deprecated test TUI",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "go run pkg/integration/deprecated/cmd/tui/main.go",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"focus": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
71
pkg/gui/background.go
Normal file
71
pkg/gui/background.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package gui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (gui *Gui) startBackgroundRoutines() {
|
||||||
|
userConfig := gui.UserConfig
|
||||||
|
|
||||||
|
if userConfig.Git.AutoFetch {
|
||||||
|
fetchInterval := userConfig.Refresher.FetchInterval
|
||||||
|
if fetchInterval > 0 {
|
||||||
|
go utils.Safe(gui.startBackgroundFetch)
|
||||||
|
} else {
|
||||||
|
gui.c.Log.Errorf(
|
||||||
|
"Value of config option 'refresher.fetchInterval' (%d) is invalid, disabling auto-fetch",
|
||||||
|
fetchInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if userConfig.Git.AutoRefresh {
|
||||||
|
refreshInterval := userConfig.Refresher.RefreshInterval
|
||||||
|
if refreshInterval > 0 {
|
||||||
|
gui.goEvery(time.Second*time.Duration(refreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules)
|
||||||
|
} else {
|
||||||
|
gui.c.Log.Errorf(
|
||||||
|
"Value of config option 'refresher.refreshInterval' (%d) is invalid, disabling auto-refresh",
|
||||||
|
refreshInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) startBackgroundFetch() {
|
||||||
|
gui.waitForIntro.Wait()
|
||||||
|
isNew := gui.IsNewRepo
|
||||||
|
userConfig := gui.UserConfig
|
||||||
|
if !isNew {
|
||||||
|
time.After(time.Duration(userConfig.Refresher.FetchInterval) * time.Second)
|
||||||
|
}
|
||||||
|
err := gui.backgroundFetch()
|
||||||
|
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
|
||||||
|
_ = gui.c.Alert(gui.c.Tr.NoAutomaticGitFetchTitle, gui.c.Tr.NoAutomaticGitFetchBody)
|
||||||
|
} else {
|
||||||
|
gui.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), gui.stopChan, func() error {
|
||||||
|
err := gui.backgroundFetch()
|
||||||
|
gui.render()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
|
||||||
|
go utils.Safe(func() {
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if gui.PauseBackgroundThreads {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_ = function()
|
||||||
|
case <-stop:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
appTypes "github.com/jesseduffield/lazygit/pkg/app/types"
|
appTypes "github.com/jesseduffield/lazygit/pkg/app/types"
|
||||||
@ -527,27 +526,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
|||||||
|
|
||||||
gui.waitForIntro.Add(1)
|
gui.waitForIntro.Add(1)
|
||||||
|
|
||||||
if userConfig.Git.AutoFetch {
|
gui.startBackgroundRoutines()
|
||||||
fetchInterval := userConfig.Refresher.FetchInterval
|
|
||||||
if fetchInterval > 0 {
|
|
||||||
go utils.Safe(gui.startBackgroundFetch)
|
|
||||||
} else {
|
|
||||||
gui.c.Log.Errorf(
|
|
||||||
"Value of config option 'refresher.fetchInterval' (%d) is invalid, disabling auto-fetch",
|
|
||||||
fetchInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if userConfig.Git.AutoRefresh {
|
|
||||||
refreshInterval := userConfig.Refresher.RefreshInterval
|
|
||||||
if refreshInterval > 0 {
|
|
||||||
gui.goEvery(time.Second*time.Duration(refreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules)
|
|
||||||
} else {
|
|
||||||
gui.c.Log.Errorf(
|
|
||||||
"Value of config option 'refresher.refreshInterval' (%d) is invalid, disabling auto-refresh",
|
|
||||||
refreshInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.c.Log.Info("starting main loop")
|
gui.c.Log.Info("starting main loop")
|
||||||
|
|
||||||
@ -722,43 +701,6 @@ func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
|
|
||||||
go utils.Safe(func() {
|
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
if gui.PauseBackgroundThreads {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_ = function()
|
|
||||||
case <-stop:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) startBackgroundFetch() {
|
|
||||||
gui.waitForIntro.Wait()
|
|
||||||
isNew := gui.IsNewRepo
|
|
||||||
userConfig := gui.UserConfig
|
|
||||||
if !isNew {
|
|
||||||
time.After(time.Duration(userConfig.Refresher.FetchInterval) * time.Second)
|
|
||||||
}
|
|
||||||
err := gui.backgroundFetch()
|
|
||||||
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
|
|
||||||
_ = gui.c.Alert(gui.c.Tr.NoAutomaticGitFetchTitle, gui.c.Tr.NoAutomaticGitFetchBody)
|
|
||||||
} else {
|
|
||||||
gui.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), gui.stopChan, func() error {
|
|
||||||
err := gui.backgroundFetch()
|
|
||||||
gui.render()
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setColorScheme sets the color scheme for the app based on the user config
|
// setColorScheme sets the color scheme for the app based on the user config
|
||||||
func (gui *Gui) setColorScheme() error {
|
func (gui *Gui) setColorScheme() error {
|
||||||
userConfig := gui.UserConfig
|
userConfig := gui.UserConfig
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
@ -55,7 +57,7 @@ func (self *GuiDriver) Fail(message string) {
|
|||||||
self.gui.g.Close()
|
self.gui.g.Close()
|
||||||
// need to give the gui time to close
|
// need to give the gui time to close
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
panic(message)
|
panic(fmt.Sprintf("%s\nLog:\n%s", message, strings.Join(self.gui.CmdLog, "\n")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// logs to the normal place that you log to i.e. viewable with `lazygit --logs`
|
// logs to the normal place that you log to i.e. viewable with `lazygit --logs`
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
@ -17,6 +18,10 @@ type IntegrationTest interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) {
|
func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) {
|
||||||
|
if os.Getenv(components.SANDBOX_ENV_VAR) == "true" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if test != nil {
|
if test != nil {
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
@ -41,10 +41,28 @@ The run step has four arguments passed in:
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Use assertions to ensure that lazygit has processed all your keybindings so far. For example, if you press 'n' on a branch to create a new branch, assert that the confirmation view is now focused.
|
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()
|
||||||
|
```
|
||||||
|
|
||||||
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 `input.PressKey(keys.Universal.Confirm)` in 100 places, it's better to have a method `input.Confirm()`. This is not to say that everything should be made into a method on the input struct: just things that are particularly common in tests.
|
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 `input.PressKey(keys.Universal.Confirm)` in 100 places, it's better to have a method `input.Confirm()`. This is not to say that everything should be made into a method on the input struct: 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. For example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// asserts that a prompt opens with the title 'Enter a file name', and then types 'my file' and confirms
|
||||||
|
input.Prompt(Equals("Enter a file name"), "my file")
|
||||||
|
|
||||||
|
// asserts that a menu opens with the title: 'Choose file content', and then selects the option which contains 'bar'
|
||||||
|
input.Menu(Equals("Choose file content"), Contains("bar"))
|
||||||
|
|
||||||
|
// asserts a confirmation appears with the title 'Are you sure?' and the content 'Are you REALLY sure' and then confirms
|
||||||
|
input.AcceptConfirmation(Equals("Are you sure?"), Equals("Are you REALLY sure?"))
|
||||||
|
```
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
There are three ways to invoke a test:
|
There are three ways to invoke a test:
|
||||||
|
@ -21,57 +21,44 @@ func NewAssert(gui integrationTypes.GuiDriver) *Assert {
|
|||||||
return &Assert{gui: gui}
|
return &Assert{gui: gui}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for making assertions on string values
|
|
||||||
type matcher struct {
|
|
||||||
testFn func(string) (bool, string)
|
|
||||||
prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *matcher) test(value string) (bool, string) {
|
|
||||||
ok, message := self.testFn(value)
|
|
||||||
if ok {
|
|
||||||
return true, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.prefix != "" {
|
|
||||||
return false, self.prefix + " " + message
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *matcher) context(prefix string) *matcher {
|
|
||||||
self.prefix = prefix
|
|
||||||
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func Contains(target string) *matcher {
|
func Contains(target string) *matcher {
|
||||||
return &matcher{testFn: func(value string) (bool, string) {
|
return NewMatcher(
|
||||||
return strings.Contains(value, target), fmt.Sprintf("Expected '%s' to be found in '%s'", target, value)
|
fmt.Sprintf("contains '%s'", target),
|
||||||
}}
|
func(value string) (bool, string) {
|
||||||
|
return strings.Contains(value, target), fmt.Sprintf("Expected '%s' to be found in '%s'", target, value)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotContains(target string) *matcher {
|
func NotContains(target string) *matcher {
|
||||||
return &matcher{testFn: func(value string) (bool, string) {
|
return NewMatcher(
|
||||||
return !strings.Contains(value, target), fmt.Sprintf("Expected '%s' to NOT be found in '%s'", target, value)
|
fmt.Sprintf("does not contain '%s'", target),
|
||||||
}}
|
func(value string) (bool, string) {
|
||||||
|
return !strings.Contains(value, target), fmt.Sprintf("Expected '%s' to NOT be found in '%s'", target, value)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MatchesRegexp(regexStr string) *matcher {
|
func MatchesRegexp(target string) *matcher {
|
||||||
return &matcher{testFn: func(value string) (bool, string) {
|
return NewMatcher(
|
||||||
matched, err := regexp.MatchString(regexStr, value)
|
fmt.Sprintf("matches regular expression '%s'", target),
|
||||||
if err != nil {
|
func(value string) (bool, string) {
|
||||||
return false, fmt.Sprintf("Unexpected error parsing regular expression '%s': %s", regexStr, err.Error())
|
matched, err := regexp.MatchString(target, value)
|
||||||
}
|
if err != nil {
|
||||||
return matched, fmt.Sprintf("Expected '%s' to match regular expression '%s'", value, regexStr)
|
return false, fmt.Sprintf("Unexpected error parsing regular expression '%s': %s", target, err.Error())
|
||||||
}}
|
}
|
||||||
|
return matched, fmt.Sprintf("Expected '%s' to match regular expression '%s'", value, target)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Equals(target string) *matcher {
|
func Equals(target string) *matcher {
|
||||||
return &matcher{testFn: func(value string) (bool, string) {
|
return NewMatcher(
|
||||||
return target == value, fmt.Sprintf("Expected '%s' to equal '%s'", value, target)
|
fmt.Sprintf("equals '%s'", target),
|
||||||
}}
|
func(value string) (bool, string) {
|
||||||
|
return target == value, fmt.Sprintf("Expected '%s' to equal '%s'", value, target)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) WorkingTreeFileCount(expectedCount int) {
|
func (self *Assert) WorkingTreeFileCount(expectedCount int) {
|
||||||
@ -115,7 +102,7 @@ func (self *Assert) AtLeastOneCommit() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchHeadCommitMessage(matcher *matcher) {
|
func (self *Assert) HeadCommitMessage(matcher *matcher) {
|
||||||
self.assertWithRetries(func() (bool, string) {
|
self.assertWithRetries(func() (bool, string) {
|
||||||
return len(self.gui.Model().Commits) > 0, "Expected at least one commit to be present"
|
return len(self.gui.Model().Commits) > 0, "Expected at least one commit to be present"
|
||||||
})
|
})
|
||||||
@ -156,7 +143,7 @@ func (self *Assert) InListContext() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchSelectedLine(matcher *matcher) {
|
func (self *Assert) SelectedLine(matcher *matcher) {
|
||||||
self.matchString(matcher, "Unexpected selected line.",
|
self.matchString(matcher, "Unexpected selected line.",
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.CurrentContext().GetView().SelectedLine()
|
return self.gui.CurrentContext().GetView().SelectedLine()
|
||||||
@ -186,13 +173,27 @@ func (self *Assert) InAlert() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Assert) InCommitMessagePanel() {
|
||||||
|
self.assertWithRetries(func() (bool, string) {
|
||||||
|
currentView := self.gui.CurrentContext().GetView()
|
||||||
|
return currentView.Name() == "commitMessage", "Expected commit message panel to be focused"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Assert) InMenu() {
|
func (self *Assert) InMenu() {
|
||||||
self.assertWithRetries(func() (bool, string) {
|
self.assertWithRetries(func() (bool, string) {
|
||||||
return self.gui.CurrentContext().GetView().Name() == "menu", "Expected popup menu to be focused"
|
return self.gui.CurrentContext().GetView().Name() == "menu", "Expected popup menu to be focused"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchCurrentViewTitle(matcher *matcher) {
|
func (self *Assert) NotInPopup() {
|
||||||
|
self.assertWithRetries(func() (bool, string) {
|
||||||
|
currentViewName := self.gui.CurrentContext().GetView().Name()
|
||||||
|
return currentViewName != "menu" && currentViewName != "confirmation" && currentViewName != "commitMessage", "Expected popup not to be focused"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Assert) CurrentViewTitle(matcher *matcher) {
|
||||||
self.matchString(matcher, "Unexpected current view title.",
|
self.matchString(matcher, "Unexpected current view title.",
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.CurrentContext().GetView().Title
|
return self.gui.CurrentContext().GetView().Title
|
||||||
@ -200,7 +201,7 @@ func (self *Assert) MatchCurrentViewTitle(matcher *matcher) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchViewContent(viewName string, matcher *matcher) {
|
func (self *Assert) ViewContent(viewName string, matcher *matcher) {
|
||||||
self.matchString(matcher, fmt.Sprintf("Unexpected content in view '%s'.", viewName),
|
self.matchString(matcher, fmt.Sprintf("Unexpected content in view '%s'.", viewName),
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.View(viewName).Buffer()
|
return self.gui.View(viewName).Buffer()
|
||||||
@ -208,7 +209,7 @@ func (self *Assert) MatchViewContent(viewName string, matcher *matcher) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchCurrentViewContent(matcher *matcher) {
|
func (self *Assert) CurrentViewContent(matcher *matcher) {
|
||||||
self.matchString(matcher, "Unexpected content in current view.",
|
self.matchString(matcher, "Unexpected content in current view.",
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.CurrentContext().GetView().Buffer()
|
return self.gui.CurrentContext().GetView().Buffer()
|
||||||
@ -216,7 +217,7 @@ func (self *Assert) MatchCurrentViewContent(matcher *matcher) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchMainViewContent(matcher *matcher) {
|
func (self *Assert) MainViewContent(matcher *matcher) {
|
||||||
self.matchString(matcher, "Unexpected main view content.",
|
self.matchString(matcher, "Unexpected main view content.",
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.MainView().Buffer()
|
return self.gui.MainView().Buffer()
|
||||||
@ -224,7 +225,7 @@ func (self *Assert) MatchMainViewContent(matcher *matcher) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) MatchSecondaryViewContent(matcher *matcher) {
|
func (self *Assert) SecondaryViewContent(matcher *matcher) {
|
||||||
self.matchString(matcher, "Unexpected secondary view title.",
|
self.matchString(matcher, "Unexpected secondary view title.",
|
||||||
func() string {
|
func() string {
|
||||||
return self.gui.SecondaryView().Buffer()
|
return self.gui.SecondaryView().Buffer()
|
||||||
@ -240,7 +241,7 @@ func (self *Assert) matchString(matcher *matcher, context string, getValue func(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Assert) assertWithRetries(test func() (bool, string)) {
|
func (self *Assert) assertWithRetries(test func() (bool, string)) {
|
||||||
waitTimes := []int{0, 1, 5, 10, 200, 500, 1000, 2000, 4000}
|
waitTimes := []int{0, 1, 1, 1, 1, 1, 5, 10, 20, 40, 100, 200, 500, 1000, 2000, 4000}
|
||||||
|
|
||||||
var message string
|
var message string
|
||||||
for _, waitTime := range waitTimes {
|
for _, waitTime := range waitTimes {
|
||||||
|
@ -28,88 +28,82 @@ func NewInput(gui integrationTypes.GuiDriver, keys config.KeybindingConfig, asse
|
|||||||
|
|
||||||
// key is something like 'w' or '<space>'. It's best not to pass a direct value,
|
// 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
|
// but instead to go through the default user config to get a more meaningful key name
|
||||||
func (self *Input) PressKeys(keyStrs ...string) {
|
func (self *Input) Press(keyStrs ...string) {
|
||||||
for _, keyStr := range keyStrs {
|
for _, keyStr := range keyStrs {
|
||||||
self.pressKey(keyStr)
|
self.press(keyStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) pressKey(keyStr string) {
|
func (self *Input) press(keyStr string) {
|
||||||
self.Wait(self.pushKeyDelay)
|
self.Wait(self.pushKeyDelay)
|
||||||
|
|
||||||
self.gui.PressKey(keyStr)
|
self.gui.PressKey(keyStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) SwitchToStatusWindow() {
|
func (self *Input) SwitchToStatusWindow() {
|
||||||
self.pressKey(self.keys.Universal.JumpToBlock[0])
|
self.press(self.keys.Universal.JumpToBlock[0])
|
||||||
self.assert.CurrentWindowName("status")
|
self.assert.CurrentWindowName("status")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) SwitchToFilesWindow() {
|
func (self *Input) SwitchToFilesWindow() {
|
||||||
self.pressKey(self.keys.Universal.JumpToBlock[1])
|
self.press(self.keys.Universal.JumpToBlock[1])
|
||||||
self.assert.CurrentWindowName("files")
|
self.assert.CurrentWindowName("files")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) SwitchToBranchesWindow() {
|
func (self *Input) SwitchToBranchesWindow() {
|
||||||
self.pressKey(self.keys.Universal.JumpToBlock[2])
|
self.press(self.keys.Universal.JumpToBlock[2])
|
||||||
self.assert.CurrentWindowName("localBranches")
|
self.assert.CurrentWindowName("localBranches")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) SwitchToCommitsWindow() {
|
func (self *Input) SwitchToCommitsWindow() {
|
||||||
self.pressKey(self.keys.Universal.JumpToBlock[3])
|
self.press(self.keys.Universal.JumpToBlock[3])
|
||||||
self.assert.CurrentWindowName("commits")
|
self.assert.CurrentWindowName("commits")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) SwitchToStashWindow() {
|
func (self *Input) SwitchToStashWindow() {
|
||||||
self.pressKey(self.keys.Universal.JumpToBlock[4])
|
self.press(self.keys.Universal.JumpToBlock[4])
|
||||||
self.assert.CurrentWindowName("stash")
|
self.assert.CurrentWindowName("stash")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) Type(content string) {
|
func (self *Input) Type(content string) {
|
||||||
for _, char := range content {
|
for _, char := range content {
|
||||||
self.pressKey(string(char))
|
self.press(string(char))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. pressing enter
|
// i.e. pressing enter
|
||||||
func (self *Input) Confirm() {
|
func (self *Input) Confirm() {
|
||||||
self.pressKey(self.keys.Universal.Confirm)
|
self.press(self.keys.Universal.Confirm)
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Input) ProceedWhenAsked(matcher *matcher) {
|
|
||||||
self.assert.InConfirm()
|
|
||||||
self.assert.MatchCurrentViewContent(matcher)
|
|
||||||
self.Confirm()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. same as Confirm
|
// i.e. same as Confirm
|
||||||
func (self *Input) Enter() {
|
func (self *Input) Enter() {
|
||||||
self.pressKey(self.keys.Universal.Confirm)
|
self.press(self.keys.Universal.Confirm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. pressing escape
|
// i.e. pressing escape
|
||||||
func (self *Input) Cancel() {
|
func (self *Input) Cancel() {
|
||||||
self.pressKey(self.keys.Universal.Return)
|
self.press(self.keys.Universal.Return)
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. pressing space
|
// i.e. pressing space
|
||||||
func (self *Input) PrimaryAction() {
|
func (self *Input) PrimaryAction() {
|
||||||
self.pressKey(self.keys.Universal.Select)
|
self.press(self.keys.Universal.Select)
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. pressing down arrow
|
// i.e. pressing down arrow
|
||||||
func (self *Input) NextItem() {
|
func (self *Input) NextItem() {
|
||||||
self.pressKey(self.keys.Universal.NextItem)
|
self.press(self.keys.Universal.NextItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
// i.e. pressing up arrow
|
// i.e. pressing up arrow
|
||||||
func (self *Input) PreviousItem() {
|
func (self *Input) PreviousItem() {
|
||||||
self.pressKey(self.keys.Universal.PrevItem)
|
self.press(self.keys.Universal.PrevItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Input) ContinueMerge() {
|
func (self *Input) ContinueMerge() {
|
||||||
self.PressKeys(self.keys.Universal.CreateRebaseOptionsMenu)
|
self.Press(self.keys.Universal.CreateRebaseOptionsMenu)
|
||||||
self.assert.MatchSelectedLine(Contains("continue"))
|
self.assert.SelectedLine(Contains("continue"))
|
||||||
self.Confirm()
|
self.Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +135,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
|
// 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,
|
// in the current page and failing that, jump to the top of the view and iterate through all of it,
|
||||||
// looking for the item.
|
// looking for the item.
|
||||||
func (self *Input) NavigateToListItemContainingText(text string) {
|
func (self *Input) NavigateToListItem(matcher *matcher) {
|
||||||
self.assert.InListContext()
|
self.assert.InListContext()
|
||||||
|
|
||||||
currentContext := self.gui.CurrentContext().(types.IListContext)
|
currentContext := self.gui.CurrentContext().(types.IListContext)
|
||||||
@ -151,19 +145,20 @@ func (self *Input) NavigateToListItemContainingText(text string) {
|
|||||||
var matchIndex int
|
var matchIndex int
|
||||||
|
|
||||||
self.assert.assertWithRetries(func() (bool, string) {
|
self.assert.assertWithRetries(func() (bool, string) {
|
||||||
matchCount := 0
|
|
||||||
matchIndex = -1
|
matchIndex = -1
|
||||||
|
var matches []string
|
||||||
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
|
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
|
||||||
for i, line := range view.ViewBufferLines() {
|
for i, line := range view.ViewBufferLines() {
|
||||||
if strings.Contains(line, text) {
|
ok, _ := matcher.test(line)
|
||||||
matchCount++
|
if ok {
|
||||||
|
matches = append(matches, line)
|
||||||
matchIndex = i
|
matchIndex = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matchCount > 1 {
|
if len(matches) > 1 {
|
||||||
return false, fmt.Sprintf("Found %d matches for %s, expected only a single match", matchCount, text)
|
return false, fmt.Sprintf("Found %d matches for `%s`, expected only a single match. Lines:\n%s", len(matches), matcher.name, strings.Join(matches, "\n"))
|
||||||
} else if matchCount == 0 {
|
} else if len(matches) == 0 {
|
||||||
return false, fmt.Sprintf("Could not find item containing text: %s", text)
|
return false, fmt.Sprintf("Could not find item matching: %s", matcher.name)
|
||||||
} else {
|
} else {
|
||||||
return true, ""
|
return true, ""
|
||||||
}
|
}
|
||||||
@ -171,20 +166,67 @@ func (self *Input) NavigateToListItemContainingText(text string) {
|
|||||||
|
|
||||||
selectedLineIdx := view.SelectedLineIdx()
|
selectedLineIdx := view.SelectedLineIdx()
|
||||||
if selectedLineIdx == matchIndex {
|
if selectedLineIdx == matchIndex {
|
||||||
self.assert.MatchSelectedLine(Contains(text))
|
self.assert.SelectedLine(matcher)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if selectedLineIdx < matchIndex {
|
if selectedLineIdx < matchIndex {
|
||||||
for i := selectedLineIdx; i < matchIndex; i++ {
|
for i := selectedLineIdx; i < matchIndex; i++ {
|
||||||
self.NextItem()
|
self.NextItem()
|
||||||
}
|
}
|
||||||
self.assert.MatchSelectedLine(Contains(text))
|
self.assert.SelectedLine(matcher)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
for i := selectedLineIdx; i > matchIndex; i-- {
|
for i := selectedLineIdx; i > matchIndex; i-- {
|
||||||
self.PreviousItem()
|
self.PreviousItem()
|
||||||
}
|
}
|
||||||
self.assert.MatchSelectedLine(Contains(text))
|
self.assert.SelectedLine(matcher)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Input) AcceptConfirmation(title *matcher, content *matcher) {
|
||||||
|
self.assert.InConfirm()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.assert.CurrentViewContent(content)
|
||||||
|
self.Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Input) DenyConfirmation(title *matcher, content *matcher) {
|
||||||
|
self.assert.InConfirm()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.assert.CurrentViewContent(content)
|
||||||
|
self.Cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Input) Prompt(title *matcher, textToType string) {
|
||||||
|
self.assert.InPrompt()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.Type(textToType)
|
||||||
|
self.Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
// type some text into a prompt, then switch to the suggestions panel and expect the first
|
||||||
|
// item to match the given matcher, then confirm that item.
|
||||||
|
func (self *Input) Typeahead(title *matcher, textToType string, expectedFirstOption *matcher) {
|
||||||
|
self.assert.InPrompt()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.Type(textToType)
|
||||||
|
self.Press(self.keys.Universal.TogglePanel)
|
||||||
|
self.assert.CurrentViewName("suggestions")
|
||||||
|
self.assert.SelectedLine(expectedFirstOption)
|
||||||
|
self.Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Input) Menu(title *matcher, optionToSelect *matcher) {
|
||||||
|
self.assert.InMenu()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.NavigateToListItem(optionToSelect)
|
||||||
|
self.Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Input) Alert(title *matcher, content *matcher) {
|
||||||
|
self.assert.InListContext()
|
||||||
|
self.assert.CurrentViewTitle(title)
|
||||||
|
self.assert.CurrentViewContent(content)
|
||||||
|
self.Confirm()
|
||||||
|
}
|
||||||
|
35
pkg/integration/components/matcher.go
Normal file
35
pkg/integration/components/matcher.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package components
|
||||||
|
|
||||||
|
// for making assertions on string values
|
||||||
|
type matcher struct {
|
||||||
|
// e.g. "contains 'foo'"
|
||||||
|
name string
|
||||||
|
// returns a bool that says whether the test passed and if it returns false, it
|
||||||
|
// also returns a string of the error message
|
||||||
|
testFn func(string) (bool, string)
|
||||||
|
// this is printed when there's an error so that it's clear what the context of the assertion is
|
||||||
|
prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMatcher(name string, testFn func(string) (bool, string)) *matcher {
|
||||||
|
return &matcher{name: name, testFn: testFn}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *matcher) test(value string) (bool, string) {
|
||||||
|
ok, message := self.testFn(value)
|
||||||
|
if ok {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.prefix != "" {
|
||||||
|
return false, self.prefix + " " + message
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *matcher) context(prefix string) *matcher {
|
||||||
|
self.prefix = prefix
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
@ -115,6 +115,10 @@ func prepareTestDir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildLazygit() error {
|
func buildLazygit() error {
|
||||||
|
// // TODO: remove this line!
|
||||||
|
// // skipping this because I'm not making changes to the app code atm.
|
||||||
|
// return nil
|
||||||
|
|
||||||
osCommand := oscommands.NewDummyOSCommand()
|
osCommand := oscommands.NewDummyOSCommand()
|
||||||
return osCommand.Cmd.New(fmt.Sprintf(
|
return osCommand.Cmd.New(fmt.Sprintf(
|
||||||
"go build -o %s pkg/integration/clients/injector/main.go", tempLazygitPath(),
|
"go build -o %s pkg/integration/clients/injector/main.go", tempLazygitPath(),
|
||||||
|
@ -35,6 +35,32 @@ func (s *Shell) RunCommand(cmdStr string) *Shell {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Shell) RunShellCommand(cmdStr string) *Shell {
|
||||||
|
cmd := secureexec.Command("sh", "-c", cmdStr)
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Dir = s.dir
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("error running shell command: %s\n%s", cmdStr, string(output)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Shell) RunShellCommandExpectError(cmdStr string) *Shell {
|
||||||
|
cmd := secureexec.Command("sh", "-c", cmdStr)
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Dir = s.dir
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
panic(fmt.Sprintf("Expected error running shell command: %s\n%s", cmdStr, string(output)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Shell) CreateFile(path string, content string) *Shell {
|
func (s *Shell) CreateFile(path string, content string) *Shell {
|
||||||
fullPath := filepath.Join(s.dir, path)
|
fullPath := filepath.Join(s.dir, path)
|
||||||
err := os.WriteFile(fullPath, []byte(content), 0o644)
|
err := os.WriteFile(fullPath, []byte(content), 0o644)
|
||||||
|
@ -64,8 +64,8 @@ func TestAssertionFailure(t *testing.T) {
|
|||||||
test := NewIntegrationTest(NewIntegrationTestArgs{
|
test := NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
Description: unitTestDescription,
|
Description: unitTestDescription,
|
||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
input.PressKeys("b")
|
input.Press("b")
|
||||||
assert.CommitCount(2)
|
assert.CommitCount(2)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -91,8 +91,8 @@ func TestSuccess(t *testing.T) {
|
|||||||
test := NewIntegrationTest(NewIntegrationTestArgs{
|
test := NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
Description: unitTestDescription,
|
Description: unitTestDescription,
|
||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
input.PressKeys("b")
|
input.Press("b")
|
||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -20,67 +20,53 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert *Assert,
|
assert *Assert,
|
||||||
keys config.KeybindingConfig,
|
keys config.KeybindingConfig,
|
||||||
) {
|
) {
|
||||||
viewBisectOptions := func() {
|
|
||||||
input.PressKeys(keys.Commits.ViewBisectOptions)
|
|
||||||
assert.InMenu()
|
|
||||||
}
|
|
||||||
markCommitAsBad := func() {
|
markCommitAsBad := func() {
|
||||||
viewBisectOptions()
|
input.Press(keys.Commits.ViewBisectOptions)
|
||||||
assert.MatchSelectedLine(Contains("bad"))
|
input.Menu(Equals("Bisect"), MatchesRegexp(`mark .* as bad`))
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
markCommitAsGood := func() {
|
markCommitAsGood := func() {
|
||||||
viewBisectOptions()
|
input.Press(keys.Commits.ViewBisectOptions)
|
||||||
assert.MatchSelectedLine(Contains("bad"))
|
input.Menu(Equals("Bisect"), MatchesRegexp(`mark .* as good`))
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("good"))
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.AtLeastOneCommit()
|
assert.AtLeastOneCommit()
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("commit 10"))
|
assert.SelectedLine(Contains("commit 10"))
|
||||||
|
|
||||||
input.NavigateToListItemContainingText("commit 09")
|
input.NavigateToListItem(Contains("commit 09"))
|
||||||
|
|
||||||
markCommitAsBad()
|
markCommitAsBad()
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("bisecting"))
|
assert.ViewContent("information", Contains("bisecting"))
|
||||||
|
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.MatchSelectedLine(Contains("<-- bad"))
|
assert.SelectedLine(Contains("<-- bad"))
|
||||||
|
|
||||||
input.NavigateToListItemContainingText("commit 02")
|
input.NavigateToListItem(Contains("commit 02"))
|
||||||
|
|
||||||
markCommitAsGood()
|
markCommitAsGood()
|
||||||
|
|
||||||
// lazygit will land us in the comit between our good and bad commits.
|
// lazygit will land us in the commit between our good and bad commits.
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.MatchSelectedLine(Contains("commit 05"))
|
assert.SelectedLine(Contains("commit 05"))
|
||||||
assert.MatchSelectedLine(Contains("<-- current"))
|
assert.SelectedLine(Contains("<-- current"))
|
||||||
|
|
||||||
markCommitAsBad()
|
markCommitAsBad()
|
||||||
|
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.MatchSelectedLine(Contains("commit 04"))
|
assert.SelectedLine(Contains("commit 04"))
|
||||||
assert.MatchSelectedLine(Contains("<-- current"))
|
assert.SelectedLine(Contains("<-- current"))
|
||||||
|
|
||||||
markCommitAsGood()
|
markCommitAsGood()
|
||||||
|
|
||||||
assert.InAlert()
|
|
||||||
assert.MatchCurrentViewContent(Contains("Bisect complete!"))
|
|
||||||
// commit 5 is the culprit because we marked 4 as good and 5 as bad.
|
// commit 5 is the culprit because we marked 4 as good and 5 as bad.
|
||||||
assert.MatchCurrentViewContent(Contains("commit 05"))
|
input.Alert(Equals("Bisect complete"), MatchesRegexp("(?s)commit 05.*Do you want to reset"))
|
||||||
assert.MatchCurrentViewContent(Contains("Do you want to reset"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.MatchCurrentViewContent(Contains("commit 04"))
|
assert.CurrentViewContent(Contains("commit 04"))
|
||||||
assert.MatchViewContent("information", NotContains("bisecting"))
|
assert.ViewContent("information", NotContains("bisecting"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -24,46 +24,29 @@ var FromOtherBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert *Assert,
|
assert *Assert,
|
||||||
keys config.KeybindingConfig,
|
keys config.KeybindingConfig,
|
||||||
) {
|
) {
|
||||||
viewBisectOptions := func() {
|
assert.ViewContent("information", Contains("bisecting"))
|
||||||
input.PressKeys(keys.Commits.ViewBisectOptions)
|
|
||||||
assert.InMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
markCommitAsGood := func() {
|
|
||||||
viewBisectOptions()
|
|
||||||
assert.MatchSelectedLine(Contains("bad"))
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("good"))
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("bisecting"))
|
|
||||||
|
|
||||||
assert.AtLeastOneCommit()
|
assert.AtLeastOneCommit()
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("<-- bad"))
|
assert.SelectedLine(Contains("<-- bad"))
|
||||||
assert.MatchSelectedLine(Contains("commit 08"))
|
assert.SelectedLine(Contains("commit 08"))
|
||||||
|
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("<-- current"))
|
assert.SelectedLine(Contains("<-- current"))
|
||||||
assert.MatchSelectedLine(Contains("commit 07"))
|
assert.SelectedLine(Contains("commit 07"))
|
||||||
|
|
||||||
markCommitAsGood()
|
input.Press(keys.Commits.ViewBisectOptions)
|
||||||
|
input.Menu(Equals("Bisect"), MatchesRegexp(`mark .* as good`))
|
||||||
|
|
||||||
assert.InAlert()
|
input.Alert(Equals("Bisect complete"), MatchesRegexp(`(?s)commit 08.*Do you want to reset`))
|
||||||
assert.MatchCurrentViewContent(Contains("Bisect complete!"))
|
|
||||||
assert.MatchCurrentViewContent(Contains("commit 08"))
|
|
||||||
assert.MatchCurrentViewContent(Contains("Do you want to reset"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.MatchViewContent("information", NotContains("bisecting"))
|
assert.ViewContent("information", NotContains("bisecting"))
|
||||||
|
|
||||||
// back in master branch which just had the one commit
|
// back in master branch which just had the one commit
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchSelectedLine(Contains("only commit on master"))
|
assert.SelectedLine(Contains("only commit on master"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -21,19 +21,16 @@ var CheckoutByName = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("master"))
|
assert.SelectedLine(Contains("master"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("@"))
|
assert.SelectedLine(Contains("@"))
|
||||||
input.PressKeys(keys.Branches.CheckoutBranchByName)
|
input.Press(keys.Branches.CheckoutBranchByName)
|
||||||
assert.InPrompt()
|
|
||||||
assert.MatchCurrentViewTitle(Equals("Branch name:"))
|
input.Prompt(Equals("Branch name:"), "new-branch")
|
||||||
input.Type("new-branch")
|
|
||||||
input.Confirm()
|
input.Alert(Equals("Branch not found"), Equals("Branch not found. Create a new branch named new-branch?"))
|
||||||
assert.InAlert()
|
|
||||||
assert.MatchCurrentViewContent(Equals("Branch not found. Create a new branch named new-branch?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
assert.MatchSelectedLine(Contains("new-branch"))
|
assert.SelectedLine(Contains("new-branch"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -20,21 +20,18 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("branch-two"))
|
assert.SelectedLine(Contains("branch-two"))
|
||||||
input.PressKeys(keys.Universal.Remove)
|
input.Press(keys.Universal.Remove)
|
||||||
assert.InAlert()
|
input.Alert(Equals("Error"), Contains("You cannot delete the checked out branch!"))
|
||||||
assert.MatchCurrentViewContent(Contains("You cannot delete the checked out branch!"))
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("branch-one"))
|
assert.SelectedLine(Contains("branch-one"))
|
||||||
input.PressKeys(keys.Universal.Remove)
|
|
||||||
assert.InConfirm()
|
input.Press(keys.Universal.Remove)
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to delete the branch 'branch-one'?"))
|
input.AcceptConfirmation(Equals("Delete Branch"), Contains("Are you sure you want to delete the branch 'branch-one'?"))
|
||||||
input.Confirm()
|
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
assert.MatchSelectedLine(Contains("master"))
|
assert.SelectedLine(Contains("master"))
|
||||||
assert.MatchCurrentViewContent(NotContains("branch-one"))
|
assert.CurrentViewContent(NotContains("branch-one"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -18,36 +18,32 @@ var Rebase = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
assert.SelectedLine(Contains("first-change-branch"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
assert.SelectedLine(Contains("second-change-branch"))
|
||||||
input.PressKeys(keys.Branches.RebaseBranch)
|
input.Press(keys.Branches.RebaseBranch)
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Rebasing"), Contains("Are you sure you want to rebase 'first-change-branch' on top of 'second-change-branch'?"))
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to rebase 'first-change-branch' on top of 'second-change-branch'?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Auto-merge failed"), Contains("Conflicts!"))
|
||||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("files")
|
assert.CurrentViewName("files")
|
||||||
assert.MatchSelectedLine(Contains("file"))
|
assert.SelectedLine(Contains("file"))
|
||||||
|
|
||||||
// not using Confirm() convenience method because I suspect we might change this
|
// not using Confirm() convenience method because I suspect we might change this
|
||||||
// keybinding to something more bespoke
|
// keybinding to something more bespoke
|
||||||
input.PressKeys(keys.Universal.Confirm)
|
input.Press(keys.Universal.Confirm)
|
||||||
|
|
||||||
assert.CurrentViewName("mergeConflicts")
|
assert.CurrentViewName("mergeConflicts")
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("rebasing"))
|
assert.ViewContent("information", Contains("rebasing"))
|
||||||
assert.InConfirm()
|
|
||||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
input.AcceptConfirmation(Equals("continue"), Contains("all merge conflicts resolved. Continue?"))
|
||||||
input.Confirm()
|
|
||||||
assert.MatchViewContent("information", NotContains("rebasing"))
|
assert.ViewContent("information", NotContains("rebasing"))
|
||||||
|
|
||||||
// this proves we actually have integrated the changes from second-change-branch
|
// this proves we actually have integrated the changes from second-change-branch
|
||||||
assert.MatchViewContent("commits", Contains("second-change-branch unrelated change"))
|
assert.ViewContent("commits", Contains("second-change-branch unrelated change"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -21,49 +21,45 @@ var RebaseAndDrop = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
assert.SelectedLine(Contains("first-change-branch"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
assert.SelectedLine(Contains("second-change-branch"))
|
||||||
input.PressKeys(keys.Branches.RebaseBranch)
|
input.Press(keys.Branches.RebaseBranch)
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Rebasing"), Contains("Are you sure you want to rebase 'first-change-branch' on top of 'second-change-branch'?"))
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to rebase 'first-change-branch' on top of 'second-change-branch'?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("rebasing"))
|
assert.ViewContent("information", Contains("rebasing"))
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Auto-merge failed"), Contains("Conflicts!"))
|
||||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("files")
|
assert.CurrentViewName("files")
|
||||||
assert.MatchSelectedLine(Contains("file"))
|
assert.SelectedLine(Contains("file"))
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.MatchSelectedLine(Contains("pick")) // this means it's a rebasing commit
|
assert.SelectedLine(Contains("pick")) // this means it's a rebasing commit
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
input.PressKeys(keys.Universal.Remove)
|
input.Press(keys.Universal.Remove)
|
||||||
assert.MatchSelectedLine(Contains("to remove"))
|
// this is the commit name
|
||||||
assert.MatchSelectedLine(Contains("drop"))
|
assert.SelectedLine(Contains("to remove"))
|
||||||
|
// the commit has been marked to drop once we continue the rebase.
|
||||||
|
assert.SelectedLine(Contains("drop"))
|
||||||
|
|
||||||
input.SwitchToFilesWindow()
|
input.SwitchToFilesWindow()
|
||||||
|
|
||||||
// not using Confirm() convenience method because I suspect we might change this
|
// not using Confirm() convenience method because I suspect we might change this
|
||||||
// keybinding to something more bespoke
|
// keybinding to something more bespoke
|
||||||
input.PressKeys(keys.Universal.Confirm)
|
input.Press(keys.Universal.Confirm)
|
||||||
|
|
||||||
assert.CurrentViewName("mergeConflicts")
|
assert.CurrentViewName("mergeConflicts")
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("continue"), Contains("all merge conflicts resolved. Continue?"))
|
||||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.MatchViewContent("information", NotContains("rebasing"))
|
assert.ViewContent("information", NotContains("rebasing"))
|
||||||
|
|
||||||
// this proves we actually have integrated the changes from second-change-branch
|
// this proves we actually have integrated the changes from second-change-branch
|
||||||
assert.MatchViewContent("commits", Contains("second-change-branch unrelated change"))
|
assert.ViewContent("commits", Contains("second-change-branch unrelated change"))
|
||||||
assert.MatchViewContent("commits", Contains("to keep"))
|
assert.ViewContent("commits", Contains("to keep"))
|
||||||
assert.MatchViewContent("commits", NotContains("to remove"))
|
assert.ViewContent("commits", NotContains("to remove"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -24,21 +24,13 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("current-branch"))
|
assert.SelectedLine(Contains("current-branch"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("other-branch"))
|
assert.SelectedLine(Contains("other-branch"))
|
||||||
|
|
||||||
input.PressKeys(keys.Commits.ViewResetOptions)
|
input.Press(keys.Commits.ViewResetOptions)
|
||||||
assert.InMenu()
|
|
||||||
assert.MatchCurrentViewTitle(Contains("reset to other-branch"))
|
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("soft reset"))
|
input.Menu(Contains("reset to other-branch"), Contains("hard reset"))
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("mixed reset"))
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("hard reset"))
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
// ensure that we've returned from the menu before continuing
|
// ensure that we've returned from the menu before continuing
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
@ -47,8 +39,8 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.CommitCount(2)
|
assert.CommitCount(2)
|
||||||
assert.MatchSelectedLine(Contains("other-branch commit"))
|
assert.SelectedLine(Contains("other-branch commit"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("root commit"))
|
assert.SelectedLine(Contains("root commit"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -24,18 +24,11 @@ var Suggestions = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
input.PressKeys(keys.Branches.CheckoutBranchByName)
|
input.Press(keys.Branches.CheckoutBranchByName)
|
||||||
assert.CurrentViewName("confirmation")
|
|
||||||
|
|
||||||
input.Type("branch-to")
|
|
||||||
|
|
||||||
input.PressKeys(keys.Universal.TogglePanel)
|
|
||||||
assert.CurrentViewName("suggestions")
|
|
||||||
|
|
||||||
// we expect the first suggestion to be the branch we want because it most
|
// we expect the first suggestion to be the branch we want because it most
|
||||||
// closely matches what we typed in
|
// closely matches what we typed in
|
||||||
assert.MatchSelectedLine(Contains("branch-to-checkout"))
|
input.Typeahead(Equals("Branch name:"), "branch-to", Contains("branch-to-checkout"))
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentBranchName("branch-to-checkout")
|
assert.CurrentBranchName("branch-to-checkout")
|
||||||
},
|
},
|
||||||
|
@ -27,40 +27,38 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("first-branch"))
|
assert.SelectedLine(Contains("first-branch"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second-branch"))
|
assert.SelectedLine(Contains("second-branch"))
|
||||||
|
|
||||||
input.Enter()
|
input.Enter()
|
||||||
|
|
||||||
assert.CurrentViewName("subCommits")
|
assert.CurrentViewName("subCommits")
|
||||||
assert.MatchSelectedLine(Contains("four"))
|
assert.SelectedLine(Contains("four"))
|
||||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
input.Press(keys.Commits.CherryPickCopy)
|
||||||
assert.MatchViewContent("information", Contains("1 commit copied"))
|
assert.ViewContent("information", Contains("1 commit copied"))
|
||||||
|
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("three"))
|
assert.SelectedLine(Contains("three"))
|
||||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
input.Press(keys.Commits.CherryPickCopy)
|
||||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
assert.ViewContent("information", Contains("2 commits copied"))
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("two"))
|
assert.SelectedLine(Contains("two"))
|
||||||
input.PressKeys(keys.Commits.PasteCommits)
|
input.Press(keys.Commits.PasteCommits)
|
||||||
assert.InAlert()
|
input.Alert(Equals("Cherry-Pick"), Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
assert.MatchSelectedLine(Contains("four"))
|
assert.SelectedLine(Contains("four"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("three"))
|
assert.SelectedLine(Contains("three"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("two"))
|
assert.SelectedLine(Contains("two"))
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
assert.ViewContent("information", Contains("2 commits copied"))
|
||||||
input.PressKeys(keys.Universal.Return)
|
input.Press(keys.Universal.Return)
|
||||||
assert.MatchViewContent("information", NotContains("commits copied"))
|
assert.ViewContent("information", NotContains("commits copied"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -18,50 +18,44 @@ var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
assert.CurrentViewName("localBranches")
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
assert.SelectedLine(Contains("first-change-branch"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
assert.SelectedLine(Contains("second-change-branch"))
|
||||||
|
|
||||||
input.Enter()
|
input.Enter()
|
||||||
|
|
||||||
assert.CurrentViewName("subCommits")
|
assert.CurrentViewName("subCommits")
|
||||||
assert.MatchSelectedLine(Contains("second-change-branch unrelated change"))
|
assert.SelectedLine(Contains("second-change-branch unrelated change"))
|
||||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
input.Press(keys.Commits.CherryPickCopy)
|
||||||
assert.MatchViewContent("information", Contains("1 commit copied"))
|
assert.ViewContent("information", Contains("1 commit copied"))
|
||||||
|
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second change"))
|
assert.SelectedLine(Contains("second change"))
|
||||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
input.Press(keys.Commits.CherryPickCopy)
|
||||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
assert.ViewContent("information", Contains("2 commits copied"))
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("first change"))
|
assert.SelectedLine(Contains("first change"))
|
||||||
input.PressKeys(keys.Commits.PasteCommits)
|
input.Press(keys.Commits.PasteCommits)
|
||||||
assert.InAlert()
|
input.Alert(Equals("Cherry-Pick"), Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
|
||||||
|
|
||||||
input.Confirm()
|
input.AcceptConfirmation(Equals("Auto-merge failed"), Contains("Conflicts!"))
|
||||||
|
|
||||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("files")
|
assert.CurrentViewName("files")
|
||||||
assert.MatchSelectedLine(Contains("file"))
|
assert.SelectedLine(Contains("file"))
|
||||||
|
|
||||||
// not using Confirm() convenience method because I suspect we might change this
|
// not using Confirm() convenience method because I suspect we might change this
|
||||||
// keybinding to something more bespoke
|
// keybinding to something more bespoke
|
||||||
input.PressKeys(keys.Universal.Confirm)
|
input.Press(keys.Universal.Confirm)
|
||||||
|
|
||||||
assert.CurrentViewName("mergeConflicts")
|
assert.CurrentViewName("mergeConflicts")
|
||||||
// picking 'Second change'
|
// picking 'Second change'
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("continue"), Contains("all merge conflicts resolved. Continue?"))
|
||||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentViewName("files")
|
assert.CurrentViewName("files")
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
@ -69,19 +63,19 @@ var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Contains("second-change-branch unrelated change"))
|
assert.SelectedLine(Contains("second-change-branch unrelated change"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("second change"))
|
assert.SelectedLine(Contains("second change"))
|
||||||
// because we picked 'Second change' when resolving the conflict,
|
// because we picked 'Second change' when resolving the conflict,
|
||||||
// we now see this commit as having replaced First Change with Second Change,
|
// we now see this commit as having replaced First Change with Second Change,
|
||||||
// as opposed to replacing 'Original' with 'Second change'
|
// as opposed to replacing 'Original' with 'Second change'
|
||||||
assert.MatchMainViewContent(Contains("-First Change"))
|
assert.MainViewContent(Contains("-First Change"))
|
||||||
assert.MatchMainViewContent(Contains("+Second Change"))
|
assert.MainViewContent(Contains("+Second Change"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Contains("first change"))
|
assert.SelectedLine(Contains("first change"))
|
||||||
|
|
||||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
assert.ViewContent("information", Contains("2 commits copied"))
|
||||||
input.PressKeys(keys.Universal.Return)
|
input.Press(keys.Universal.Return)
|
||||||
assert.MatchViewContent("information", NotContains("commits copied"))
|
assert.ViewContent("information", NotContains("commits copied"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -20,13 +20,14 @@ var Commit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.PressKeys(keys.Files.CommitChanges)
|
input.Press(keys.Files.CommitChanges)
|
||||||
|
|
||||||
|
assert.InCommitMessagePanel()
|
||||||
commitMessage := "my commit message"
|
commitMessage := "my commit message"
|
||||||
input.Type(commitMessage)
|
input.Type(commitMessage)
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchHeadCommitMessage(Equals(commitMessage))
|
assert.HeadCommitMessage(Equals(commitMessage))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -17,18 +17,19 @@ var CommitMultiline = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
|
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.PressKeys(keys.Files.CommitChanges)
|
input.Press(keys.Files.CommitChanges)
|
||||||
|
|
||||||
|
assert.InCommitMessagePanel()
|
||||||
input.Type("first line")
|
input.Type("first line")
|
||||||
input.PressKeys(keys.Universal.AppendNewline)
|
input.Press(keys.Universal.AppendNewline)
|
||||||
input.PressKeys(keys.Universal.AppendNewline)
|
input.Press(keys.Universal.AppendNewline)
|
||||||
input.Type("third line")
|
input.Type("third line")
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchHeadCommitMessage(Equals("first line"))
|
assert.HeadCommitMessage(Equals("first line"))
|
||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.MatchMainViewContent(MatchesRegexp("first line\n\\s*\n\\s*third line"))
|
assert.MainViewContent(MatchesRegexp("first line\n\\s*\n\\s*third line"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -23,16 +23,13 @@ var NewBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
|
|
||||||
input.PressKeys(keys.Universal.New)
|
input.Press(keys.Universal.New)
|
||||||
|
|
||||||
assert.CurrentViewName("confirmation")
|
|
||||||
|
|
||||||
branchName := "my-branch-name"
|
branchName := "my-branch-name"
|
||||||
input.Type(branchName)
|
input.Prompt(Contains("New Branch Name"), branchName)
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CommitCount(2)
|
assert.CommitCount(2)
|
||||||
assert.MatchHeadCommitMessage(Contains("commit 2"))
|
assert.HeadCommitMessage(Contains("commit 2"))
|
||||||
assert.CurrentBranchName(branchName)
|
assert.CurrentBranchName(branchName)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -20,18 +20,13 @@ var Revert = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
|
|
||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
|
|
||||||
input.PressKeys(keys.Commits.RevertCommit)
|
input.Press(keys.Commits.RevertCommit)
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Revert commit"), MatchesRegexp(`Are you sure you want to revert \w+?`))
|
||||||
assert.MatchCurrentViewTitle(Equals("Revert commit"))
|
|
||||||
assert.MatchCurrentViewContent(MatchesRegexp("Are you sure you want to revert \\w+?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CommitCount(2)
|
assert.CommitCount(2)
|
||||||
assert.MatchHeadCommitMessage(Contains("Revert \"first commit\""))
|
assert.HeadCommitMessage(Contains("Revert \"first commit\""))
|
||||||
input.PreviousItem()
|
input.PreviousItem()
|
||||||
assert.MatchMainViewContent(Contains("-myfile content"))
|
assert.MainViewContent(Contains("-myfile content"))
|
||||||
assert.FileSystemPathNotPresent("myfile")
|
assert.FileSystemPathNotPresent("myfile")
|
||||||
|
|
||||||
input.Wait(10)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -18,17 +18,36 @@ var Staged = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
assert.CurrentViewName("files")
|
||||||
|
assert.SelectedLine(Contains("myfile"))
|
||||||
|
// stage the file
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.Confirm()
|
input.Enter()
|
||||||
input.PrimaryAction()
|
assert.CurrentViewName("stagingSecondary")
|
||||||
input.PressKeys(keys.Files.CommitChanges)
|
// we start with both lines having been staged
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+myfile content"))
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+with a second line"))
|
||||||
|
assert.ViewContent("staging", NotContains("+myfile content"))
|
||||||
|
assert.ViewContent("staging", NotContains("+with a second line"))
|
||||||
|
|
||||||
|
// unstage the selected line
|
||||||
|
input.PrimaryAction()
|
||||||
|
|
||||||
|
// the line should have been moved to the main view
|
||||||
|
assert.ViewContent("stagingSecondary", NotContains("+myfile content"))
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+with a second line"))
|
||||||
|
assert.ViewContent("staging", Contains("+myfile content"))
|
||||||
|
assert.ViewContent("staging", NotContains("+with a second line"))
|
||||||
|
|
||||||
|
input.Press(keys.Files.CommitChanges)
|
||||||
commitMessage := "my commit message"
|
commitMessage := "my commit message"
|
||||||
input.Type(commitMessage)
|
input.Type(commitMessage)
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchHeadCommitMessage(Equals(commitMessage))
|
assert.HeadCommitMessage(Equals(commitMessage))
|
||||||
assert.CurrentWindowName("stagingSecondary")
|
assert.CurrentWindowName("stagingSecondary")
|
||||||
|
|
||||||
|
// TODO: assert that the staging panel has been refreshed (it currently does not get correctly refreshed)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -18,17 +18,38 @@ var StagedWithoutHooks = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
// stage the file
|
||||||
|
assert.CurrentViewName("files")
|
||||||
|
assert.SelectedLine(Contains("myfile"))
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.Confirm()
|
input.Enter()
|
||||||
input.PrimaryAction()
|
assert.CurrentViewName("stagingSecondary")
|
||||||
input.PressKeys(keys.Files.CommitChangesWithoutHook)
|
// we start with both lines having been staged
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+myfile content"))
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+with a second line"))
|
||||||
|
assert.ViewContent("staging", NotContains("+myfile content"))
|
||||||
|
assert.ViewContent("staging", NotContains("+with a second line"))
|
||||||
|
|
||||||
commitMessage := "my commit message"
|
// unstage the selected line
|
||||||
|
input.PrimaryAction()
|
||||||
|
|
||||||
|
// the line should have been moved to the main view
|
||||||
|
assert.ViewContent("stagingSecondary", NotContains("+myfile content"))
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+with a second line"))
|
||||||
|
assert.ViewContent("staging", Contains("+myfile content"))
|
||||||
|
assert.ViewContent("staging", NotContains("+with a second line"))
|
||||||
|
|
||||||
|
input.Press(keys.Files.CommitChangesWithoutHook)
|
||||||
|
assert.InCommitMessagePanel()
|
||||||
|
assert.CurrentViewContent(Contains("WIP"))
|
||||||
|
commitMessage := ": my commit message"
|
||||||
input.Type(commitMessage)
|
input.Type(commitMessage)
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchHeadCommitMessage(Equals("WIP" + commitMessage))
|
assert.HeadCommitMessage(Equals("WIP" + commitMessage))
|
||||||
assert.CurrentWindowName("stagingSecondary")
|
assert.CurrentViewName("stagingSecondary")
|
||||||
|
|
||||||
|
// TODO: assert that the staging panel has been refreshed (it currently does not get correctly refreshed)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: find out why we can't use assert.SelectedLine() on the staging/stagingSecondary views.
|
||||||
|
|
||||||
var Unstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
var Unstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
Description: "Staging a couple files, going in the unstaged files menu, staging a line and committing",
|
Description: "Staging a couple files, going in the unstaged files menu, staging a line and committing",
|
||||||
ExtraCmdArgs: "",
|
ExtraCmdArgs: "",
|
||||||
@ -18,16 +20,26 @@ var Unstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
|
|
||||||
input.Confirm()
|
assert.CurrentViewName("files")
|
||||||
|
assert.SelectedLine(Contains("myfile"))
|
||||||
|
input.Enter()
|
||||||
|
assert.CurrentViewName("staging")
|
||||||
|
assert.ViewContent("stagingSecondary", NotContains("+myfile content"))
|
||||||
|
// stage the first line
|
||||||
input.PrimaryAction()
|
input.PrimaryAction()
|
||||||
input.PressKeys(keys.Files.CommitChanges)
|
assert.ViewContent("staging", NotContains("+myfile content"))
|
||||||
|
assert.ViewContent("stagingSecondary", Contains("+myfile content"))
|
||||||
|
|
||||||
|
input.Press(keys.Files.CommitChanges)
|
||||||
|
assert.InCommitMessagePanel()
|
||||||
commitMessage := "my commit message"
|
commitMessage := "my commit message"
|
||||||
input.Type(commitMessage)
|
input.Type(commitMessage)
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
assert.MatchHeadCommitMessage(Equals(commitMessage))
|
assert.HeadCommitMessage(Equals(commitMessage))
|
||||||
assert.CurrentWindowName("staging")
|
assert.CurrentWindowName("staging")
|
||||||
|
|
||||||
|
// TODO: assert that the staging panel has been refreshed (it currently does not get correctly refreshed)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
package commit
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
|
||||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
|
||||||
)
|
|
||||||
|
|
||||||
var UnstagedWithoutHooks = NewIntegrationTest(NewIntegrationTestArgs{
|
|
||||||
Description: "Staging a couple files, going in the unstaged files menu, staging a line and committing without pre-commit hooks",
|
|
||||||
ExtraCmdArgs: "",
|
|
||||||
Skip: false,
|
|
||||||
SetupConfig: func(config *config.AppConfig) {},
|
|
||||||
SetupRepo: func(shell *Shell) {
|
|
||||||
shell.
|
|
||||||
CreateFile("myfile", "myfile content\nwith a second line").
|
|
||||||
CreateFile("myfile2", "myfile2 content")
|
|
||||||
},
|
|
||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
|
||||||
assert.CommitCount(0)
|
|
||||||
|
|
||||||
input.Confirm()
|
|
||||||
input.PrimaryAction()
|
|
||||||
input.PressKeys(keys.Files.CommitChangesWithoutHook)
|
|
||||||
|
|
||||||
commitMessage := "my commit message"
|
|
||||||
input.Type(commitMessage)
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CommitCount(1)
|
|
||||||
assert.MatchHeadCommitMessage(Equals("WIP" + commitMessage))
|
|
||||||
assert.CurrentWindowName("staging")
|
|
||||||
},
|
|
||||||
})
|
|
@ -29,8 +29,8 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
) {
|
) {
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
assert.WorkingTreeFileCount(1)
|
assert.WorkingTreeFileCount(1)
|
||||||
assert.MatchSelectedLine(Contains("myfile"))
|
assert.SelectedLine(Contains("myfile"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -63,26 +63,16 @@ var FormPrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
) {
|
) {
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
|
|
||||||
assert.InPrompt()
|
input.Prompt(Equals("Enter a file name"), "my file")
|
||||||
assert.MatchCurrentViewTitle(Equals("Enter a file name"))
|
|
||||||
input.Type("my file")
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InMenu()
|
input.Menu(Equals("Choose file content"), Contains("bar"))
|
||||||
assert.MatchCurrentViewTitle(Equals("Choose file content"))
|
|
||||||
assert.MatchSelectedLine(Contains("foo"))
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("bar"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Are you sure?"), Equals("Are you REALLY sure you want to make this file? Up to you buddy."))
|
||||||
assert.MatchCurrentViewTitle(Equals("Are you sure?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.WorkingTreeFileCount(1)
|
assert.WorkingTreeFileCount(1)
|
||||||
assert.MatchSelectedLine(Contains("my file"))
|
assert.SelectedLine(Contains("my file"))
|
||||||
assert.MatchMainViewContent(Contains(`"BAR"`))
|
assert.MainViewContent(Contains(`"BAR"`))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -51,24 +51,16 @@ var MenuFromCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
|
|
||||||
assert.InMenu()
|
input.Menu(Equals("Choose commit message"), Contains("bar"))
|
||||||
assert.MatchCurrentViewTitle(Equals("Choose commit message"))
|
|
||||||
assert.MatchSelectedLine(Equals("baz"))
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Equals("bar"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InPrompt()
|
input.Prompt(Equals("Description"), " my branch")
|
||||||
assert.MatchCurrentViewTitle(Equals("Description"))
|
|
||||||
input.Type(" my branch")
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
input.SwitchToFilesWindow()
|
input.SwitchToFilesWindow()
|
||||||
|
|
||||||
assert.WorkingTreeFileCount(1)
|
assert.WorkingTreeFileCount(1)
|
||||||
assert.MatchSelectedLine(Contains("output.txt"))
|
assert.SelectedLine(Contains("output.txt"))
|
||||||
assert.MatchMainViewContent(Contains("bar Branch: #feature/foo my branch feature/foo"))
|
assert.MainViewContent(Contains("bar Branch: #feature/foo my branch feature/foo"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -47,22 +47,19 @@ var MenuFromCommandsOutput = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert *Assert,
|
assert *Assert,
|
||||||
keys config.KeybindingConfig,
|
keys config.KeybindingConfig,
|
||||||
) {
|
) {
|
||||||
|
assert.CurrentBranchName("feature/bar")
|
||||||
|
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
input.SwitchToBranchesWindow()
|
input.SwitchToBranchesWindow()
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
|
|
||||||
assert.InPrompt()
|
assert.InPrompt()
|
||||||
assert.MatchCurrentViewTitle(Equals("Which git command do you want to run?"))
|
assert.CurrentViewTitle(Equals("Which git command do you want to run?"))
|
||||||
assert.MatchSelectedLine(Equals("branch"))
|
assert.SelectedLine(Equals("branch"))
|
||||||
input.Confirm()
|
input.Confirm()
|
||||||
|
|
||||||
assert.InMenu()
|
input.Menu(Equals("Branch:"), Equals("master"))
|
||||||
assert.MatchCurrentViewTitle(Equals("Branch:"))
|
|
||||||
input.NextItem()
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Equals("master"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.CurrentBranchName("master")
|
assert.CurrentBranchName("master")
|
||||||
},
|
},
|
||||||
|
@ -61,26 +61,16 @@ var MultiplePrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
) {
|
) {
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Press("a")
|
||||||
|
|
||||||
assert.InPrompt()
|
input.Prompt(Equals("Enter a file name"), "myfile")
|
||||||
assert.MatchCurrentViewTitle(Equals("Enter a file name"))
|
|
||||||
input.Type("myfile")
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InMenu()
|
input.Menu(Equals("Choose file content"), Contains("bar"))
|
||||||
assert.MatchCurrentViewTitle(Equals("Choose file content"))
|
|
||||||
assert.MatchSelectedLine(Contains("foo"))
|
|
||||||
input.NextItem()
|
|
||||||
assert.MatchSelectedLine(Contains("bar"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals("Are you sure?"), Equals("Are you REALLY sure you want to make this file? Up to you buddy."))
|
||||||
assert.MatchCurrentViewTitle(Equals("Are you sure?"))
|
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.WorkingTreeFileCount(1)
|
assert.WorkingTreeFileCount(1)
|
||||||
assert.MatchSelectedLine(Contains("myfile"))
|
assert.SelectedLine(Contains("myfile"))
|
||||||
assert.MatchMainViewContent(Contains("BAR"))
|
assert.MainViewContent(Contains("BAR"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
57
pkg/integration/tests/diff/diff.go
Normal file
57
pkg/integration/tests/diff/diff.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package diff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Diff = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "View the diff of two branches, then view the reverse diff",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.NewBranch("branch-a")
|
||||||
|
shell.CreateFileAndAdd("file1", "first line")
|
||||||
|
shell.Commit("first commit")
|
||||||
|
|
||||||
|
shell.NewBranch("branch-b")
|
||||||
|
shell.UpdateFileAndAdd("file1", "first line\nsecond line")
|
||||||
|
shell.Commit("update")
|
||||||
|
|
||||||
|
shell.Checkout("branch-a")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
input.SwitchToBranchesWindow()
|
||||||
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
|
assert.SelectedLine(Contains("branch-a"))
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
input.Menu(Equals("Diffing"), Contains(`diff branch-a`))
|
||||||
|
|
||||||
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff branch-a branch-a"))
|
||||||
|
input.NextItem()
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff branch-a branch-b"))
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
|
||||||
|
input.Enter()
|
||||||
|
assert.CurrentViewName("subCommits")
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
assert.SelectedLine(Contains("update"))
|
||||||
|
input.Enter()
|
||||||
|
assert.CurrentViewName("commitFiles")
|
||||||
|
assert.SelectedLine(Contains("file1"))
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
|
||||||
|
input.Press(keys.Universal.Return)
|
||||||
|
input.Press(keys.Universal.Return)
|
||||||
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
input.Menu(Equals("Diffing"), Contains("reverse diff direction"))
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff branch-a branch-b -R"))
|
||||||
|
assert.MainViewContent(Contains("-second line"))
|
||||||
|
},
|
||||||
|
})
|
66
pkg/integration/tests/diff/diff_and_apply_patch.go
Normal file
66
pkg/integration/tests/diff/diff_and_apply_patch.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package diff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiffAndApplyPatch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Create a patch from the diff between two branches and apply the patch.",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.NewBranch("branch-a")
|
||||||
|
shell.CreateFileAndAdd("file1", "first line\n")
|
||||||
|
shell.Commit("first commit")
|
||||||
|
|
||||||
|
shell.NewBranch("branch-b")
|
||||||
|
shell.UpdateFileAndAdd("file1", "first line\nsecond line\n")
|
||||||
|
shell.Commit("update")
|
||||||
|
|
||||||
|
shell.Checkout("branch-a")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
input.SwitchToBranchesWindow()
|
||||||
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
|
assert.SelectedLine(Contains("branch-a"))
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
|
||||||
|
input.Menu(Equals("Diffing"), Equals("diff branch-a"))
|
||||||
|
|
||||||
|
assert.CurrentViewName("localBranches")
|
||||||
|
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff branch-a branch-a"))
|
||||||
|
input.NextItem()
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff branch-a branch-b"))
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
|
||||||
|
input.Enter()
|
||||||
|
assert.CurrentViewName("subCommits")
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
assert.SelectedLine(Contains("update"))
|
||||||
|
input.Enter()
|
||||||
|
assert.CurrentViewName("commitFiles")
|
||||||
|
assert.SelectedLine(Contains("file1"))
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
|
||||||
|
// add the file to the patch
|
||||||
|
input.PrimaryAction()
|
||||||
|
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
input.Menu(Equals("Diffing"), Contains("exit diff mode"))
|
||||||
|
|
||||||
|
assert.ViewContent("information", NotContains("building patch"))
|
||||||
|
|
||||||
|
input.Press(keys.Universal.CreatePatchOptionsMenu)
|
||||||
|
// adding the regex '$' here to distinguish the menu item from the 'apply patch in reverse' item
|
||||||
|
input.Menu(Equals("Patch Options"), MatchesRegexp("apply patch$"))
|
||||||
|
|
||||||
|
input.SwitchToFilesWindow()
|
||||||
|
|
||||||
|
assert.SelectedLine(Contains("file1"))
|
||||||
|
assert.MainViewContent(Contains("+second line"))
|
||||||
|
},
|
||||||
|
})
|
53
pkg/integration/tests/diff/diff_commits.go
Normal file
53
pkg/integration/tests/diff/diff_commits.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package diff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiffCommits = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "View the diff between two commits",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateFileAndAdd("file1", "first line\n")
|
||||||
|
shell.Commit("first commit")
|
||||||
|
shell.UpdateFileAndAdd("file1", "first line\nsecond line\n")
|
||||||
|
shell.Commit("second commit")
|
||||||
|
shell.UpdateFileAndAdd("file1", "first line\nsecond line\nthird line\n")
|
||||||
|
shell.Commit("third commit")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
input.SwitchToCommitsWindow()
|
||||||
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
|
assert.SelectedLine(Contains("third commit"))
|
||||||
|
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
input.Menu(Equals("Diffing"), MatchesRegexp(`diff \w+`))
|
||||||
|
|
||||||
|
assert.NotInPopup()
|
||||||
|
|
||||||
|
assert.ViewContent("information", Contains("showing output for: git diff"))
|
||||||
|
|
||||||
|
input.NextItem()
|
||||||
|
input.NextItem()
|
||||||
|
|
||||||
|
assert.SelectedLine(Contains("first commit"))
|
||||||
|
|
||||||
|
assert.MainViewContent(Contains("-second line\n-third line"))
|
||||||
|
|
||||||
|
input.Press(keys.Universal.DiffingMenu)
|
||||||
|
input.Menu(Equals("Diffing"), Contains("reverse diff direction"))
|
||||||
|
assert.NotInPopup()
|
||||||
|
|
||||||
|
assert.MainViewContent(Contains("+second line\n+third line"))
|
||||||
|
|
||||||
|
input.Enter()
|
||||||
|
|
||||||
|
assert.CurrentViewName("commitFiles")
|
||||||
|
assert.SelectedLine(Contains("file1"))
|
||||||
|
assert.MainViewContent(Contains("+second line\n+third line"))
|
||||||
|
},
|
||||||
|
})
|
@ -24,9 +24,9 @@ var DirWithUntrackedFile = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
assert.CommitCount(1)
|
assert.CommitCount(1)
|
||||||
|
|
||||||
assert.MatchMainViewContent(NotContains("error: Could not access"))
|
assert.MainViewContent(NotContains("error: Could not access"))
|
||||||
// we show baz because it's a modified file but we don't show bar because it's untracked
|
// we show baz because it's a modified file but we don't show bar because it's untracked
|
||||||
// (though it would be cool if we could show that too)
|
// (though it would be cool if we could show that too)
|
||||||
assert.MatchMainViewContent(Contains("baz"))
|
assert.MainViewContent(Contains("baz"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
123
pkg/integration/tests/file/discard_changes.go
Normal file
123
pkg/integration/tests/file/discard_changes.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiscardChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Discarding all possible permutations of changed files",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: true, // failing due to index.lock file being created
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
// typically we would use more bespoke shell methods here, but I struggled to find a way to do that,
|
||||||
|
// and this is copied over from a legacy integration test which did everything in a big shell script
|
||||||
|
// so I'm just copying it across.
|
||||||
|
|
||||||
|
// common stuff
|
||||||
|
shell.RunShellCommand(`echo test > both-deleted.txt`)
|
||||||
|
shell.RunShellCommand(`git checkout -b conflict && git add both-deleted.txt`)
|
||||||
|
shell.RunShellCommand(`echo bothmodded > both-modded.txt && git add both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo haha > deleted-them.txt && git add deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`echo haha2 > deleted-us.txt && git add deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod > modded.txt & git add modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod > modded-staged.txt & git add modded-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo del > deleted.txt && git add deleted.txt`)
|
||||||
|
shell.RunShellCommand(`echo del > deleted-staged.txt && git add deleted-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo change-delete > change-delete.txt && git add change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`echo delete-change > delete-change.txt && git add delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo double-modded > double-modded.txt && git add double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo "renamed\nhaha" > renamed.txt && git add renamed.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m one`)
|
||||||
|
|
||||||
|
// stuff on other branch
|
||||||
|
shell.RunShellCommand(`git branch conflict_second && git mv both-deleted.txt added-them-changed-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "both-deleted.txt renamed in added-them-changed-us.txt"`)
|
||||||
|
shell.RunShellCommand(`echo blah > both-added.txt && git add both-added.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod1 > both-modded.txt && git add both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`rm deleted-them.txt && git add deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`echo modded > deleted-us.txt && git add deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "two"`)
|
||||||
|
|
||||||
|
// stuff on our branch
|
||||||
|
shell.RunShellCommand(`git checkout conflict_second`)
|
||||||
|
shell.RunShellCommand(`git mv both-deleted.txt changed-them-added-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "both-deleted.txt renamed in changed-them-added-us.txt"`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > both-modded.txt && git add both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo blah2 > both-added.txt && git add both-added.txt`)
|
||||||
|
shell.RunShellCommand(`echo modded > deleted-them.txt && git add deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`rm deleted-us.txt && git add deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "three"`)
|
||||||
|
shell.RunShellCommand(`git reset --hard conflict_second`)
|
||||||
|
shell.RunShellCommandExpectError(`git merge conflict`)
|
||||||
|
|
||||||
|
shell.RunShellCommand(`echo "new" > new.txt`)
|
||||||
|
shell.RunShellCommand(`echo "new staged" > new-staged.txt && git add new-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > modded-staged.txt && git add modded-staged.txt`)
|
||||||
|
shell.RunShellCommand(`rm deleted.txt`)
|
||||||
|
shell.RunShellCommand(`rm deleted-staged.txt && git add deleted-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo change-delete2 > change-delete.txt && git add change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`rm change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`rm delete-change.txt && git add delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo "changed" > delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo "change1" > double-modded.txt && git add double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo "change2" > double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo before > added-changed.txt && git add added-changed.txt`)
|
||||||
|
shell.RunShellCommand(`echo after > added-changed.txt`)
|
||||||
|
shell.RunShellCommand(`rm renamed.txt && git add renamed.txt`)
|
||||||
|
shell.RunShellCommand(`echo "renamed\nhaha" > renamed2.txt && git add renamed2.txt`)
|
||||||
|
},
|
||||||
|
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
assert.CommitCount(3)
|
||||||
|
|
||||||
|
type statusFile struct {
|
||||||
|
status string
|
||||||
|
label string
|
||||||
|
menuTitle string
|
||||||
|
}
|
||||||
|
|
||||||
|
discardOneByOne := func(files []statusFile) {
|
||||||
|
for _, file := range files {
|
||||||
|
assert.SelectedLine(Contains(file.status + " " + file.label))
|
||||||
|
input.Press(keys.Universal.Remove)
|
||||||
|
input.Menu(Equals(file.menuTitle), Contains("discard all changes"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discardOneByOne([]statusFile{
|
||||||
|
{status: "UA", label: "added-them-changed-us.txt", menuTitle: "added-them-changed-us.txt"},
|
||||||
|
{status: "AA", label: "both-added.txt", menuTitle: "both-added.txt"},
|
||||||
|
{status: "DD", label: "both-deleted.txt", menuTitle: "both-deleted.txt"},
|
||||||
|
{status: "UU", label: "both-modded.txt", menuTitle: "both-modded.txt"},
|
||||||
|
{status: "AU", label: "changed-them-added-us.txt", menuTitle: "changed-them-added-us.txt"},
|
||||||
|
{status: "UD", label: "deleted-them.txt", menuTitle: "deleted-them.txt"},
|
||||||
|
{status: "DU", label: "deleted-us.txt", menuTitle: "deleted-us.txt"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.InConfirm()
|
||||||
|
assert.CurrentViewTitle(Contains("continue"))
|
||||||
|
assert.CurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
||||||
|
input.Press(keys.Universal.Return)
|
||||||
|
|
||||||
|
discardOneByOne([]statusFile{
|
||||||
|
{status: "MD", label: "change-delete.txt", menuTitle: "change-delete.txt"},
|
||||||
|
{status: "D ", label: "delete-change.txt", menuTitle: "delete-change.txt"},
|
||||||
|
{status: "D ", label: "deleted-staged.txt", menuTitle: "deleted-staged.txt"},
|
||||||
|
{status: " D", label: "deleted.txt", menuTitle: "deleted.txt"},
|
||||||
|
{status: "MM", label: "double-modded.txt", menuTitle: "double-modded.txt"},
|
||||||
|
{status: "M ", label: "modded-staged.txt", menuTitle: "modded-staged.txt"},
|
||||||
|
{status: " M", label: "modded.txt", menuTitle: "modded.txt"},
|
||||||
|
// the menu title only includes the new file
|
||||||
|
{status: "R ", label: "renamed.txt → renamed2.txt", menuTitle: "renamed2.txt"},
|
||||||
|
{status: "AM", label: "added-changed.txt", menuTitle: "added-changed.txt"},
|
||||||
|
{status: "A ", label: "new-staged.txt", menuTitle: "new-staged.txt"},
|
||||||
|
{status: "??", label: "new.txt", menuTitle: "new.txt"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.WorkingTreeFileCount(0)
|
||||||
|
},
|
||||||
|
})
|
@ -34,17 +34,17 @@ var AmendMerge = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
mergeCommitMessage := "Merge branch 'feature-branch' into development-branch"
|
mergeCommitMessage := "Merge branch 'feature-branch' into development-branch"
|
||||||
assert.MatchHeadCommitMessage(Contains(mergeCommitMessage))
|
assert.HeadCommitMessage(Contains(mergeCommitMessage))
|
||||||
|
|
||||||
input.PressKeys(keys.Commits.AmendToCommit)
|
input.Press(keys.Commits.AmendToCommit)
|
||||||
input.ProceedWhenAsked(Contains("Are you sure you want to amend this commit with your staged files?"))
|
input.AcceptConfirmation(Equals("Amend Commit"), Contains("Are you sure you want to amend this commit with your staged files?"))
|
||||||
|
|
||||||
// assuring we haven't added a brand new commit
|
// assuring we haven't added a brand new commit
|
||||||
assert.CommitCount(3)
|
assert.CommitCount(3)
|
||||||
assert.MatchHeadCommitMessage(Contains(mergeCommitMessage))
|
assert.HeadCommitMessage(Contains(mergeCommitMessage))
|
||||||
|
|
||||||
// assuring the post-merge file shows up in the merge commit.
|
// assuring the post-merge file shows up in the merge commit.
|
||||||
assert.MatchMainViewContent(Contains(postMergeFilename))
|
assert.MainViewContent(Contains(postMergeFilename))
|
||||||
assert.MatchMainViewContent(Contains("++" + postMergeFileContent))
|
assert.MainViewContent(Contains("++" + postMergeFileContent))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -18,21 +18,21 @@ var One = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToCommitsWindow()
|
input.SwitchToCommitsWindow()
|
||||||
assert.CurrentViewName("commits")
|
assert.CurrentViewName("commits")
|
||||||
|
|
||||||
input.NavigateToListItemContainingText("commit 02")
|
input.NavigateToListItem(Contains("commit 02"))
|
||||||
input.PressKeys(keys.Universal.Edit)
|
input.Press(keys.Universal.Edit)
|
||||||
assert.MatchSelectedLine(Contains("YOU ARE HERE"))
|
assert.SelectedLine(Contains("YOU ARE HERE"))
|
||||||
|
|
||||||
input.PreviousItem()
|
input.PreviousItem()
|
||||||
input.PressKeys(keys.Commits.MarkCommitAsFixup)
|
input.Press(keys.Commits.MarkCommitAsFixup)
|
||||||
assert.MatchSelectedLine(Contains("fixup"))
|
assert.SelectedLine(Contains("fixup"))
|
||||||
|
|
||||||
input.PreviousItem()
|
input.PreviousItem()
|
||||||
input.PressKeys(keys.Universal.Remove)
|
input.Press(keys.Universal.Remove)
|
||||||
assert.MatchSelectedLine(Contains("drop"))
|
assert.SelectedLine(Contains("drop"))
|
||||||
|
|
||||||
input.PreviousItem()
|
input.PreviousItem()
|
||||||
input.PressKeys(keys.Commits.SquashDown)
|
input.Press(keys.Commits.SquashDown)
|
||||||
assert.MatchSelectedLine(Contains("squash"))
|
assert.SelectedLine(Contains("squash"))
|
||||||
|
|
||||||
input.ContinueRebase()
|
input.ContinueRebase()
|
||||||
|
|
||||||
|
@ -11,15 +11,12 @@ var ConfirmOnQuit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.UserConfig.ConfirmOnQuit = true
|
config.UserConfig.ConfirmOnQuit = true
|
||||||
config.UserConfig.Gui.Theme.ActiveBorderColor = []string{"red"}
|
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {},
|
SetupRepo: func(shell *Shell) {},
|
||||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
assert.CommitCount(0)
|
assert.CommitCount(0)
|
||||||
|
|
||||||
input.PressKeys(keys.Universal.Quit)
|
input.Press(keys.Universal.Quit)
|
||||||
assert.InConfirm()
|
input.AcceptConfirmation(Equals(""), Contains("Are you sure you want to quit?"))
|
||||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to quit?"))
|
|
||||||
input.Confirm()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -22,16 +22,13 @@ var Rename = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
input.SwitchToStashWindow()
|
input.SwitchToStashWindow()
|
||||||
assert.CurrentViewName("stash")
|
assert.CurrentViewName("stash")
|
||||||
|
|
||||||
assert.MatchSelectedLine(Equals("On master: bar"))
|
assert.SelectedLine(Equals("On master: bar"))
|
||||||
input.NextItem()
|
input.NextItem()
|
||||||
assert.MatchSelectedLine(Equals("On master: foo"))
|
assert.SelectedLine(Equals("On master: foo"))
|
||||||
input.PressKeys(keys.Stash.RenameStash)
|
input.Press(keys.Stash.RenameStash)
|
||||||
assert.InPrompt()
|
|
||||||
assert.MatchCurrentViewTitle(Equals("Rename stash: stash@{1}"))
|
|
||||||
|
|
||||||
input.Type(" baz")
|
input.Prompt(Equals("Rename stash: stash@{1}"), " baz")
|
||||||
input.Confirm()
|
|
||||||
|
|
||||||
assert.MatchSelectedLine(Equals("On master: foo baz"))
|
assert.SelectedLine(Equals("On master: foo baz"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -19,15 +19,12 @@ var Stash = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.StashCount(0)
|
assert.StashCount(0)
|
||||||
assert.WorkingTreeFileCount(1)
|
assert.WorkingTreeFileCount(1)
|
||||||
|
|
||||||
input.PressKeys(keys.Files.ViewStashOptions)
|
input.Press(keys.Files.ViewStashOptions)
|
||||||
assert.InMenu()
|
|
||||||
|
|
||||||
input.PressKeys("a")
|
input.Menu(Equals("Stash options"), MatchesRegexp("stash all changes$"))
|
||||||
assert.InPrompt()
|
|
||||||
assert.MatchCurrentViewTitle(Equals("Stash changes"))
|
input.Prompt(Equals("Stash changes"), "my stashed file")
|
||||||
|
|
||||||
input.Type("my stashed file")
|
|
||||||
input.Confirm()
|
|
||||||
assert.StashCount(1)
|
assert.StashCount(1)
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
},
|
},
|
||||||
|
@ -20,15 +20,12 @@ var StashIncludingUntrackedFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
assert.StashCount(0)
|
assert.StashCount(0)
|
||||||
assert.WorkingTreeFileCount(2)
|
assert.WorkingTreeFileCount(2)
|
||||||
|
|
||||||
input.PressKeys(keys.Files.ViewStashOptions)
|
input.Press(keys.Files.ViewStashOptions)
|
||||||
assert.InMenu()
|
|
||||||
|
|
||||||
input.PressKeys("U")
|
input.Menu(Equals("Stash options"), Contains("stash all changes including untracked files"))
|
||||||
assert.InPrompt()
|
|
||||||
assert.MatchCurrentViewTitle(Equals("Stash changes"))
|
input.Prompt(Equals("Stash changes"), "my stashed file")
|
||||||
|
|
||||||
input.Type("my stashed file")
|
|
||||||
input.Confirm()
|
|
||||||
assert.StashCount(1)
|
assert.StashCount(1)
|
||||||
assert.WorkingTreeFileCount(0)
|
assert.WorkingTreeFileCount(0)
|
||||||
},
|
},
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/commit"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/commit"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/config"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands"
|
"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/file"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
||||||
@ -44,19 +45,22 @@ var tests = []*components.IntegrationTest{
|
|||||||
commit.Staged,
|
commit.Staged,
|
||||||
commit.Unstaged,
|
commit.Unstaged,
|
||||||
commit.StagedWithoutHooks,
|
commit.StagedWithoutHooks,
|
||||||
commit.UnstagedWithoutHooks,
|
|
||||||
custom_commands.Basic,
|
custom_commands.Basic,
|
||||||
custom_commands.FormPrompts,
|
custom_commands.FormPrompts,
|
||||||
custom_commands.MenuFromCommand,
|
custom_commands.MenuFromCommand,
|
||||||
custom_commands.MenuFromCommandsOutput,
|
custom_commands.MenuFromCommandsOutput,
|
||||||
custom_commands.MultiplePrompts,
|
custom_commands.MultiplePrompts,
|
||||||
file.DirWithUntrackedFile,
|
file.DirWithUntrackedFile,
|
||||||
|
file.DiscardChanges,
|
||||||
interactive_rebase.AmendMerge,
|
interactive_rebase.AmendMerge,
|
||||||
interactive_rebase.One,
|
interactive_rebase.One,
|
||||||
stash.Rename,
|
stash.Rename,
|
||||||
stash.Stash,
|
stash.Stash,
|
||||||
stash.StashIncludingUntrackedFiles,
|
stash.StashIncludingUntrackedFiles,
|
||||||
config.RemoteNamedStar,
|
config.RemoteNamedStar,
|
||||||
|
diff.Diff,
|
||||||
|
diff.DiffAndApplyPatch,
|
||||||
|
diff.DiffCommits,
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTests() []*components.IntegrationTest {
|
func GetTests() []*components.IntegrationTest {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
test
|
|
@ -1 +0,0 @@
|
|||||||
ref: refs/heads/branch2
|
|
@ -1,10 +0,0 @@
|
|||||||
[core]
|
|
||||||
repositoryformatversion = 0
|
|
||||||
filemode = true
|
|
||||||
bare = false
|
|
||||||
logallrefupdates = true
|
|
||||||
ignorecase = true
|
|
||||||
precomposeunicode = true
|
|
||||||
[user]
|
|
||||||
email = CI@example.com
|
|
||||||
name = CI
|
|
@ -1 +0,0 @@
|
|||||||
Unnamed repository; edit this file 'description' to name the repository.
|
|
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
# git ls-files --others --exclude-from=.git/info/exclude
|
|
||||||
# Lines that start with '#' are comments.
|
|
||||||
# For a project mostly in C, the following would be a good set of
|
|
||||||
# exclude patterns (uncomment them if you want to use them):
|
|
||||||
# *.[oa]
|
|
||||||
# *~
|
|
||||||
.DS_Store
|
|
@ -1,9 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 5751731b38a36f8eb54a4bb304522ca539e04522 CI <CI@example.com> 1617680560 +1000 commit (initial): file0
|
|
||||||
5751731b38a36f8eb54a4bb304522ca539e04522 d15e253139400c94b42fc266641d1698720d4ecf CI <CI@example.com> 1617680560 +1000 commit: file1
|
|
||||||
d15e253139400c94b42fc266641d1698720d4ecf 0519814b4923f4639f1a47348b1539e3c5c54904 CI <CI@example.com> 1617680560 +1000 commit: file2
|
|
||||||
0519814b4923f4639f1a47348b1539e3c5c54904 144da8a531224129210249f43dded86056891506 CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
||||||
144da8a531224129210249f43dded86056891506 144da8a531224129210249f43dded86056891506 CI <CI@example.com> 1617680561 +1000 checkout: moving from master to branch2
|
|
||||||
144da8a531224129210249f43dded86056891506 96a6d041bbb131df0e74d179c3adcd2ace0e7f9c CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
||||||
96a6d041bbb131df0e74d179c3adcd2ace0e7f9c 75b31f81dd4387724638dbd3aff7380155c672cd CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
||||||
75b31f81dd4387724638dbd3aff7380155c672cd f677ef8a14ca2770e48129cc13acfa1c369908cc CI <CI@example.com> 1617680561 +1000 commit: file2
|
|
||||||
f677ef8a14ca2770e48129cc13acfa1c369908cc a100b407f33fd2e97a3cb6f62b68ed6b7cc6c676 CI <CI@example.com> 1617680570 +1000 commit: test
|
|
@ -1,5 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 144da8a531224129210249f43dded86056891506 CI <CI@example.com> 1617680561 +1000 branch: Created from HEAD
|
|
||||||
144da8a531224129210249f43dded86056891506 96a6d041bbb131df0e74d179c3adcd2ace0e7f9c CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
||||||
96a6d041bbb131df0e74d179c3adcd2ace0e7f9c 75b31f81dd4387724638dbd3aff7380155c672cd CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
||||||
75b31f81dd4387724638dbd3aff7380155c672cd f677ef8a14ca2770e48129cc13acfa1c369908cc CI <CI@example.com> 1617680561 +1000 commit: file2
|
|
||||||
f677ef8a14ca2770e48129cc13acfa1c369908cc a100b407f33fd2e97a3cb6f62b68ed6b7cc6c676 CI <CI@example.com> 1617680570 +1000 commit: test
|
|
@ -1,4 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 5751731b38a36f8eb54a4bb304522ca539e04522 CI <CI@example.com> 1617680560 +1000 commit (initial): file0
|
|
||||||
5751731b38a36f8eb54a4bb304522ca539e04522 d15e253139400c94b42fc266641d1698720d4ecf CI <CI@example.com> 1617680560 +1000 commit: file1
|
|
||||||
d15e253139400c94b42fc266641d1698720d4ecf 0519814b4923f4639f1a47348b1539e3c5c54904 CI <CI@example.com> 1617680560 +1000 commit: file2
|
|
||||||
0519814b4923f4639f1a47348b1539e3c5c54904 144da8a531224129210249f43dded86056891506 CI <CI@example.com> 1617680561 +1000 commit: file4
|
|
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
|||||||
x�ÎA
|
|
||||||
Â0@Q×9Eö‚d’I2"BW=Æ$N°`l)<¾=‚ÛÏ[üºö¾ìOcWµ‘ÅieR ÌU²ÔK–B…°EŸK’æÉ™Mv}ë"0d¦À
s@*k¨±Fd‡F>ã¹îvšíušïú•¾½ôR×~³� 'r1�=ƒsÎõ˜ú'7my)šéÍ8N
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
|||||||
x+)JMU03c040031QHヒフI5`ーアコイ燹ヨカwチ�w.ス��モ[H
|
|
||||||
矢y�5�来ミ(桍ァ^-ンW(x9
|
|
@ -1,2 +0,0 @@
|
|||||||
xŤŽK
|
|
||||||
�0@»Î)f_(3ů�Rpĺ1&ăHSERčń+=AwŹÇ[<Ůj]P¶—v¨Â„)ŠdĚ,Ěvrq.’8‡yrjFź}ôdv>ôŐ ¤@ÉQqźe§%xöĄ8ôÁZáŕ˛ţĐđ»=·†úa|č‡ëľęM¶zŠ”b‡!"\ ÍiĎ©¦ćf^V%óHr8â
|
|
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
x�ÎM
|
|
||||||
Â0@a×9Eö‚dò33¡«cšL°ÐØR"x|{·�oñòÖÚÒ-þÒU«D˜¼—ì™Ñ¯³`Õ�«Ä*Iiàƒ˜]}wKiPJ‰�‰|ÄÀe.Aj¥ÀRÊH>#ŸþÚ;Nö>NOýJÛW½å=, ²Kö
|
|
||||||
Î9sÖsªëŸÜÔeUo~b,9O
|
|
@ -1 +0,0 @@
|
|||||||
a100b407f33fd2e97a3cb6f62b68ed6b7cc6c676
|
|
@ -1 +0,0 @@
|
|||||||
144da8a531224129210249f43dded86056891506
|
|
@ -1 +0,0 @@
|
|||||||
test0
|
|
@ -1 +0,0 @@
|
|||||||
test1
|
|
@ -1 +0,0 @@
|
|||||||
test2
|
|
@ -1 +0,0 @@
|
|||||||
line one
|
|
@ -1 +0,0 @@
|
|||||||
{"KeyEvents":[{"Timestamp":497,"Mod":0,"Key":259,"Ch":0},{"Timestamp":1570,"Mod":0,"Key":256,"Ch":87},{"Timestamp":1882,"Mod":0,"Key":13,"Ch":13},{"Timestamp":2258,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2514,"Mod":0,"Key":13,"Ch":13},{"Timestamp":3602,"Mod":0,"Key":13,"Ch":13},{"Timestamp":5057,"Mod":0,"Key":256,"Ch":32},{"Timestamp":5250,"Mod":0,"Key":258,"Ch":0},{"Timestamp":5410,"Mod":0,"Key":256,"Ch":32},{"Timestamp":6010,"Mod":2,"Key":16,"Ch":16},{"Timestamp":6730,"Mod":0,"Key":258,"Ch":0},{"Timestamp":7106,"Mod":0,"Key":13,"Ch":13},{"Timestamp":8090,"Mod":0,"Key":260,"Ch":0},{"Timestamp":8330,"Mod":0,"Key":256,"Ch":99},{"Timestamp":8545,"Mod":0,"Key":256,"Ch":116},{"Timestamp":8601,"Mod":0,"Key":256,"Ch":101},{"Timestamp":8778,"Mod":0,"Key":256,"Ch":115},{"Timestamp":8809,"Mod":0,"Key":256,"Ch":116},{"Timestamp":9074,"Mod":0,"Key":13,"Ch":13},{"Timestamp":9722,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]}
|
|
@ -1,40 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cd $1
|
|
||||||
|
|
||||||
git init
|
|
||||||
|
|
||||||
git config user.email "CI@example.com"
|
|
||||||
git config user.name "CI"
|
|
||||||
|
|
||||||
echo test0 > file0
|
|
||||||
git add .
|
|
||||||
git commit -am file0
|
|
||||||
|
|
||||||
echo test1 > file1
|
|
||||||
git add .
|
|
||||||
git commit -am file1
|
|
||||||
|
|
||||||
echo test2 > file2
|
|
||||||
git add .
|
|
||||||
git commit -am file2
|
|
||||||
|
|
||||||
echo "line one" > file4
|
|
||||||
git add .
|
|
||||||
git commit -am file4
|
|
||||||
|
|
||||||
git checkout -b branch2
|
|
||||||
|
|
||||||
echo "line two" >> file4
|
|
||||||
git add .
|
|
||||||
git commit -am file4
|
|
||||||
|
|
||||||
echo "line three" >> file4
|
|
||||||
git add .
|
|
||||||
git commit -am file4
|
|
||||||
|
|
||||||
echo "line two" >> file2
|
|
||||||
git add .
|
|
||||||
git commit -am file2
|
|
@ -1 +0,0 @@
|
|||||||
{ "description": "diffing two branches and making a patch from their diff files", "speed": 10 }
|
|
@ -1 +0,0 @@
|
|||||||
asd
|
|
@ -1 +0,0 @@
|
|||||||
ref: refs/heads/branch2
|
|
@ -1,10 +0,0 @@
|
|||||||
[core]
|
|
||||||
repositoryformatversion = 0
|
|
||||||
filemode = true
|
|
||||||
bare = false
|
|
||||||
logallrefupdates = true
|
|
||||||
ignorecase = true
|
|
||||||
precomposeunicode = true
|
|
||||||
[user]
|
|
||||||
email = CI@example.com
|
|
||||||
name = CI
|
|
@ -1 +0,0 @@
|
|||||||
Unnamed repository; edit this file 'description' to name the repository.
|
|
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
# git ls-files --others --exclude-from=.git/info/exclude
|
|
||||||
# Lines that start with '#' are comments.
|
|
||||||
# For a project mostly in C, the following would be a good set of
|
|
||||||
# exclude patterns (uncomment them if you want to use them):
|
|
||||||
# *.[oa]
|
|
||||||
# *~
|
|
||||||
.DS_Store
|
|
@ -1,9 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 7bf3d13079ced18f5b00e29c48c777e23f687d0a CI <CI@example.com> 1617680651 +1000 commit (initial): file0
|
|
||||||
7bf3d13079ced18f5b00e29c48c777e23f687d0a e876c3dfe2826621bea1bd3c87c2b9e2be88e69e CI <CI@example.com> 1617680651 +1000 commit: file1
|
|
||||||
e876c3dfe2826621bea1bd3c87c2b9e2be88e69e c6756882cc166f52b096a5e4fb9e4f5d507870c8 CI <CI@example.com> 1617680651 +1000 commit: file2
|
|
||||||
c6756882cc166f52b096a5e4fb9e4f5d507870c8 06da465196938ea235323950ee451ffb36a431cf CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
||||||
06da465196938ea235323950ee451ffb36a431cf 06da465196938ea235323950ee451ffb36a431cf CI <CI@example.com> 1617680651 +1000 checkout: moving from master to branch2
|
|
||||||
06da465196938ea235323950ee451ffb36a431cf 6d04f5ed53b383c0a4c63cac168df557b6df1e44 CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
||||||
6d04f5ed53b383c0a4c63cac168df557b6df1e44 a11d868e88adb55a48fc55ee1377b3255c0cd329 CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
||||||
a11d868e88adb55a48fc55ee1377b3255c0cd329 1b74d64fe4055d4502ac600072586068b27d4aa7 CI <CI@example.com> 1617680651 +1000 commit: file2
|
|
||||||
1b74d64fe4055d4502ac600072586068b27d4aa7 0804f2069f5af172770da3d231be982ca320bf8b CI <CI@example.com> 1617680662 +1000 commit: asd
|
|
@ -1,5 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 06da465196938ea235323950ee451ffb36a431cf CI <CI@example.com> 1617680651 +1000 branch: Created from HEAD
|
|
||||||
06da465196938ea235323950ee451ffb36a431cf 6d04f5ed53b383c0a4c63cac168df557b6df1e44 CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
||||||
6d04f5ed53b383c0a4c63cac168df557b6df1e44 a11d868e88adb55a48fc55ee1377b3255c0cd329 CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
||||||
a11d868e88adb55a48fc55ee1377b3255c0cd329 1b74d64fe4055d4502ac600072586068b27d4aa7 CI <CI@example.com> 1617680651 +1000 commit: file2
|
|
||||||
1b74d64fe4055d4502ac600072586068b27d4aa7 0804f2069f5af172770da3d231be982ca320bf8b CI <CI@example.com> 1617680662 +1000 commit: asd
|
|
@ -1,4 +0,0 @@
|
|||||||
0000000000000000000000000000000000000000 7bf3d13079ced18f5b00e29c48c777e23f687d0a CI <CI@example.com> 1617680651 +1000 commit (initial): file0
|
|
||||||
7bf3d13079ced18f5b00e29c48c777e23f687d0a e876c3dfe2826621bea1bd3c87c2b9e2be88e69e CI <CI@example.com> 1617680651 +1000 commit: file1
|
|
||||||
e876c3dfe2826621bea1bd3c87c2b9e2be88e69e c6756882cc166f52b096a5e4fb9e4f5d507870c8 CI <CI@example.com> 1617680651 +1000 commit: file2
|
|
||||||
c6756882cc166f52b096a5e4fb9e4f5d507870c8 06da465196938ea235323950ee451ffb36a431cf CI <CI@example.com> 1617680651 +1000 commit: file4
|
|
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user