1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-01 13:17:53 +02:00

177 lines
5.2 KiB
Go
Raw Normal View History

2022-08-12 09:19:39 +10:00
package components
2022-08-09 20:27:44 +10:00
import (
"fmt"
"strings"
"time"
2023-01-26 13:25:56 +11:00
"github.com/atotto/clipboard"
2022-08-09 20:27:44 +10:00
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
)
2022-12-27 21:35:36 +11:00
type TestDriver struct {
gui integrationTypes.GuiDriver
keys config.KeybindingConfig
2022-08-09 20:27:44 +10:00
pushKeyDelay int
*assertionHelper
2022-12-27 21:47:37 +11:00
shell *Shell
2022-08-09 20:27:44 +10:00
}
2022-12-27 21:47:37 +11:00
func NewTestDriver(gui integrationTypes.GuiDriver, shell *Shell, keys config.KeybindingConfig, pushKeyDelay int) *TestDriver {
2022-12-27 21:35:36 +11:00
return &TestDriver{
2022-12-27 15:22:31 +11:00
gui: gui,
keys: keys,
pushKeyDelay: pushKeyDelay,
assertionHelper: &assertionHelper{gui: gui},
2022-12-27 21:47:37 +11:00
shell: shell,
2022-08-09 20:27:44 +10:00
}
}
// 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
2022-12-27 21:35:36 +11:00
func (self *TestDriver) press(keyStr string) {
2022-08-09 20:27:44 +10:00
self.Wait(self.pushKeyDelay)
self.gui.PressKey(keyStr)
}
2022-12-27 21:35:36 +11:00
func (self *TestDriver) typeContent(content string) {
2022-08-09 20:27:44 +10:00
for _, char := range content {
self.press(string(char))
2022-08-09 20:27:44 +10:00
}
}
2022-12-28 10:54:38 +11:00
func (self *TestDriver) Actions() *Actions {
return &Actions{t: self}
2022-08-09 20:27:44 +10:00
}
// for when you want to allow lazygit to process something before continuing
2022-12-27 21:35:36 +11:00
func (self *TestDriver) Wait(milliseconds int) {
2022-08-09 20:27:44 +10:00
time.Sleep(time.Duration(milliseconds) * time.Millisecond)
}
2022-12-27 21:35:36 +11:00
func (self *TestDriver) LogUI(message string) {
2022-08-09 20:27:44 +10:00
self.gui.LogUI(message)
}
2022-12-27 21:35:36 +11:00
func (self *TestDriver) Log(message string) {
2022-08-09 20:27:44 +10:00
self.gui.LogUI(message)
}
2022-12-27 21:47:37 +11:00
// allows the user to run shell commands during the test to emulate background activity
func (self *TestDriver) Shell() *Shell {
return self.shell
}
// this will look for a list item in the current panel and if it finds it, it will
// enter the keypresses required to navigate to it.
// The test will fail if:
2022-08-12 09:24:39 +10:00
// - the user is not in a list item
// - no list item is found containing the given text
// - multiple list items are found containing the given text in the initial page of items
//
2022-08-09 20:27:44 +10:00
// NOTE: this currently assumes that ViewBufferLines returns all the lines that can be accessed.
// If this changes in future, we'll need to update this code to first attempt to find the item
// in the current page and failing that, jump to the top of the view and iterate through all of it,
// looking for the item.
2022-12-27 21:35:36 +11:00
func (self *TestDriver) navigateToListItem(matcher *matcher) {
2022-12-27 15:22:31 +11:00
self.inListContext()
2022-08-09 20:27:44 +10:00
currentContext := self.gui.CurrentContext().(types.IListContext)
view := currentContext.GetView()
var matchIndex int
self.assertWithRetries(func() (bool, string) {
matchIndex = -1
var matches []string
2022-12-26 17:15:33 +11:00
lines := view.ViewBufferLines()
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
2022-12-26 17:15:33 +11:00
for i, line := range lines {
ok, _ := matcher.test(line)
if ok {
matches = append(matches, line)
matchIndex = i
}
2022-08-09 20:27:44 +10:00
}
if len(matches) > 1 {
2022-12-26 17:15:33 +11:00
return false, fmt.Sprintf("Found %d matches for `%s`, expected only a single match. Matching lines:\n%s", len(matches), matcher.name(), strings.Join(matches, "\n"))
} else if len(matches) == 0 {
2022-12-26 17:15:33 +11:00
return false, fmt.Sprintf("Could not find item matching: %s. Lines:\n%s", matcher.name(), strings.Join(lines, "\n"))
} else {
return true, ""
}
})
selectedLineIdx := view.SelectedLineIdx()
if selectedLineIdx == matchIndex {
self.Views().current().SelectedLine(matcher)
return
2022-08-09 20:27:44 +10:00
}
if selectedLineIdx < matchIndex {
for i := selectedLineIdx; i < matchIndex; i++ {
self.Views().current().SelectNextItem()
2022-08-09 20:27:44 +10:00
}
self.Views().current().SelectedLine(matcher)
return
} else {
for i := selectedLineIdx; i > matchIndex; i-- {
self.Views().current().SelectPreviousItem()
2022-08-09 20:27:44 +10:00
}
self.Views().current().SelectedLine(matcher)
return
2022-08-09 20:27:44 +10:00
}
}
2022-12-27 21:35:36 +11:00
func (self *TestDriver) inListContext() {
2022-12-27 15:22:31 +11:00
self.assertWithRetries(func() (bool, string) {
currentContext := self.gui.CurrentContext()
_, ok := currentContext.(types.IListContext)
return ok, fmt.Sprintf("Expected current context to be a list context, but got %s", currentContext.GetKey())
})
}
// for making assertions on lazygit views
2022-12-27 21:35:36 +11:00
func (self *TestDriver) Views() *Views {
return &Views{t: self}
}
2022-12-28 11:00:22 +11:00
// for interacting with popups
func (self *TestDriver) ExpectPopup() *Popup {
return &Popup{t: self}
}
2023-01-26 13:25:56 +11:00
func (self *TestDriver) ExpectToast(matcher *matcher) {
self.Views().AppStatus().Content(matcher)
}
func (self *TestDriver) ExpectClipboard(matcher *matcher) {
self.assertWithRetries(func() (bool, string) {
text, err := clipboard.ReadAll()
if err != nil {
return false, "Error occured when reading from clipboard: " + err.Error()
}
ok, _ := matcher.test(text)
return ok, fmt.Sprintf("Expected clipboard to match %s, but got %s", matcher.name(), text)
})
}
2022-12-27 22:52:20 +11:00
// for making assertions through git itself
func (self *TestDriver) Git() *Git {
return &Git{assertionHelper: self.assertionHelper, shell: self.shell}
}
// for making assertions on the file system
2022-12-27 21:35:36 +11:00
func (self *TestDriver) FileSystem() *FileSystem {
return &FileSystem{assertionHelper: self.assertionHelper}
}
// for when you just want to fail the test yourself.
// This runs callbacks to ensure we render the error after closing the gui.
2022-12-27 21:35:36 +11:00
func (self *TestDriver) Fail(message string) {
self.assertionHelper.fail(message)
}