1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-01-08 04:04:22 +02:00
lazygit/pkg/gui/gui_driver.go
Jesse Duffield ab3004bcd5 Show unacknowledged toast message upon integration test failure
Often if a test fails and there's an unaknowledged toast message, that message will
explain why the test failed. Given that we don't display toast messages in
integration tests when they run (for reasons I can't recall right now), we need to
log it as part of the error message.
2024-01-19 10:50:49 +11:00

164 lines
3.7 KiB
Go

package gui
import (
"fmt"
"os"
"strings"
"time"
"github.com/gdamore/tcell/v2"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
)
// this gives our integration test a way of interacting with the gui for sending keypresses
// and reading state.
type GuiDriver struct {
gui *Gui
isIdleChan chan struct{}
toastChan chan string
}
var _ integrationTypes.GuiDriver = &GuiDriver{}
func (self *GuiDriver) PressKey(keyStr string) {
self.CheckAllToastsAcknowledged()
key := keybindings.GetKey(keyStr)
var r rune
var tcellKey tcell.Key
switch v := key.(type) {
case rune:
r = v
tcellKey = tcell.KeyRune
case gocui.Key:
tcellKey = tcell.Key(v)
}
self.gui.g.ReplayedEvents.Keys <- gocui.NewTcellKeyEventWrapper(
tcell.NewEventKey(tcellKey, r, tcell.ModNone),
0,
)
self.waitTillIdle()
}
func (self *GuiDriver) Click(x, y int) {
self.CheckAllToastsAcknowledged()
self.gui.g.ReplayedEvents.MouseEvents <- gocui.NewTcellMouseEventWrapper(
tcell.NewEventMouse(x, y, tcell.ButtonPrimary, 0),
0,
)
self.waitTillIdle()
}
// wait until lazygit is idle (i.e. all processing is done) before continuing
func (self *GuiDriver) waitTillIdle() {
<-self.isIdleChan
}
func (self *GuiDriver) CheckAllToastsAcknowledged() {
if t := self.NextToast(); t != nil {
self.Fail("Toast not acknowledged: " + *t)
}
}
func (self *GuiDriver) Keys() config.KeybindingConfig {
return self.gui.Config.GetUserConfig().Keybinding
}
func (self *GuiDriver) CurrentContext() types.Context {
return self.gui.c.CurrentContext()
}
func (self *GuiDriver) ContextForView(viewName string) types.Context {
context, ok := self.gui.helpers.View.ContextForView(viewName)
if !ok {
return nil
}
return context
}
func (self *GuiDriver) Fail(message string) {
currentView := self.gui.g.CurrentView()
// Check for unacknowledged toast: it may give us a hint as to why the test failed
toastMessage := ""
if t := self.NextToast(); t != nil {
toastMessage = fmt.Sprintf("Unacknowledged toast message: %s\n", *t)
}
fullMessage := fmt.Sprintf(
"%s\nFinal Lazygit state:\n%s\nUpon failure, focused view was '%s'.\n%sLog:\n%s", message,
self.gui.g.Snapshot(),
currentView.Name(),
toastMessage,
strings.Join(self.gui.GuiLog, "\n"),
)
self.gui.g.Close()
// need to give the gui time to close
time.Sleep(time.Millisecond * 100)
_, err := fmt.Fprintln(os.Stderr, fullMessage)
if err != nil {
panic("Test failed. Failed writing to stderr")
}
panic("Test failed")
}
// logs to the normal place that you log to i.e. viewable with `lazygit --logs`
func (self *GuiDriver) Log(message string) {
self.gui.c.Log.Warn(message)
}
// logs in the actual UI (in the commands panel)
func (self *GuiDriver) LogUI(message string) {
self.gui.c.LogAction(message)
}
func (self *GuiDriver) CheckedOutRef() *models.Branch {
return self.gui.helpers.Refs.GetCheckedOutRef()
}
func (self *GuiDriver) MainView() *gocui.View {
return self.gui.mainView()
}
func (self *GuiDriver) SecondaryView() *gocui.View {
return self.gui.secondaryView()
}
func (self *GuiDriver) View(viewName string) *gocui.View {
view, err := self.gui.g.View(viewName)
if err != nil {
panic(err)
}
return view
}
func (self *GuiDriver) SetCaption(caption string) {
self.gui.setCaption(caption)
self.waitTillIdle()
}
func (self *GuiDriver) SetCaptionPrefix(prefix string) {
self.gui.setCaptionPrefix(prefix)
self.waitTillIdle()
}
func (self *GuiDriver) NextToast() *string {
select {
case t := <-self.toastChan:
return &t
default:
return nil
}
}