mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-01-08 04:04:22 +02:00
7569180cac
We now change directories to the repo on startup so we don't need to determine the test path in some special way
226 lines
5.8 KiB
Go
226 lines
5.8 KiB
Go
package components
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/generics/slices"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
// IntegrationTest describes an integration test that will be run against the lazygit gui.
|
|
|
|
// our unit tests will use this description to avoid a panic caused by attempting
|
|
// to get the test's name via it's file's path.
|
|
const unitTestDescription = "test test"
|
|
|
|
const (
|
|
defaultWidth = 100
|
|
defaultHeight = 100
|
|
)
|
|
|
|
type IntegrationTest struct {
|
|
name string
|
|
description string
|
|
extraCmdArgs []string
|
|
extraEnvVars map[string]string
|
|
skip bool
|
|
setupRepo func(shell *Shell)
|
|
setupConfig func(config *config.AppConfig)
|
|
run func(
|
|
testDriver *TestDriver,
|
|
keys config.KeybindingConfig,
|
|
)
|
|
gitVersion GitVersionRestriction
|
|
width int
|
|
height int
|
|
}
|
|
|
|
var _ integrationTypes.IntegrationTest = &IntegrationTest{}
|
|
|
|
type NewIntegrationTestArgs struct {
|
|
// Briefly describes what happens in the test and what it's testing for
|
|
Description string
|
|
// prepares a repo for testing
|
|
SetupRepo func(shell *Shell)
|
|
// takes a config and mutates. The mutated context will end up being passed to the gui
|
|
SetupConfig func(config *config.AppConfig)
|
|
// runs the test
|
|
Run func(t *TestDriver, keys config.KeybindingConfig)
|
|
// additional args passed to lazygit
|
|
ExtraCmdArgs []string
|
|
// for when a test is flakey
|
|
ExtraEnvVars map[string]string
|
|
Skip bool
|
|
// to run a test only on certain git versions
|
|
GitVersion GitVersionRestriction
|
|
// width and height when running in headless mode, for testing
|
|
// the UI in different sizes.
|
|
// If these are set, the test must be run in headless mode
|
|
Width int
|
|
Height int
|
|
}
|
|
|
|
type GitVersionRestriction struct {
|
|
// Only one of these fields can be non-empty; use functions below to construct
|
|
from string
|
|
before string
|
|
includes []string
|
|
}
|
|
|
|
// Verifies the version is at least the given version (inclusive)
|
|
func AtLeast(version string) GitVersionRestriction {
|
|
return GitVersionRestriction{from: version}
|
|
}
|
|
|
|
// Verifies the version is before the given version (exclusive)
|
|
func Before(version string) GitVersionRestriction {
|
|
return GitVersionRestriction{before: version}
|
|
}
|
|
|
|
func Includes(versions ...string) GitVersionRestriction {
|
|
return GitVersionRestriction{includes: versions}
|
|
}
|
|
|
|
func (self GitVersionRestriction) shouldRunOnVersion(version *git_commands.GitVersion) bool {
|
|
if self.from != "" {
|
|
from, err := git_commands.ParseGitVersion(self.from)
|
|
if err != nil {
|
|
panic("Invalid git version string: " + self.from)
|
|
}
|
|
return !version.IsOlderThanVersion(from)
|
|
}
|
|
if self.before != "" {
|
|
before, err := git_commands.ParseGitVersion(self.before)
|
|
if err != nil {
|
|
panic("Invalid git version string: " + self.before)
|
|
}
|
|
return version.IsOlderThanVersion(before)
|
|
}
|
|
if len(self.includes) != 0 {
|
|
return slices.Some(self.includes, func(str string) bool {
|
|
v, err := git_commands.ParseGitVersion(str)
|
|
if err != nil {
|
|
panic("Invalid git version string: " + str)
|
|
}
|
|
return version.Major == v.Major && version.Minor == v.Minor && version.Patch == v.Patch
|
|
})
|
|
}
|
|
return true
|
|
}
|
|
|
|
func NewIntegrationTest(args NewIntegrationTestArgs) *IntegrationTest {
|
|
name := ""
|
|
if args.Description != unitTestDescription {
|
|
// this panics if we're in a unit test for our integration tests,
|
|
// so we're using "test test" as a sentinel value
|
|
name = testNameFromCurrentFilePath()
|
|
}
|
|
|
|
return &IntegrationTest{
|
|
name: name,
|
|
description: args.Description,
|
|
extraCmdArgs: args.ExtraCmdArgs,
|
|
extraEnvVars: args.ExtraEnvVars,
|
|
skip: args.Skip,
|
|
setupRepo: args.SetupRepo,
|
|
setupConfig: args.SetupConfig,
|
|
run: args.Run,
|
|
gitVersion: args.GitVersion,
|
|
width: args.Width,
|
|
height: args.Height,
|
|
}
|
|
}
|
|
|
|
func (self *IntegrationTest) Name() string {
|
|
return self.name
|
|
}
|
|
|
|
func (self *IntegrationTest) Description() string {
|
|
return self.description
|
|
}
|
|
|
|
func (self *IntegrationTest) ExtraCmdArgs() []string {
|
|
return self.extraCmdArgs
|
|
}
|
|
|
|
func (self *IntegrationTest) ExtraEnvVars() map[string]string {
|
|
return self.extraEnvVars
|
|
}
|
|
|
|
func (self *IntegrationTest) Skip() bool {
|
|
return self.skip
|
|
}
|
|
|
|
func (self *IntegrationTest) ShouldRunForGitVersion(version *git_commands.GitVersion) bool {
|
|
return self.gitVersion.shouldRunOnVersion(version)
|
|
}
|
|
|
|
func (self *IntegrationTest) SetupConfig(config *config.AppConfig) {
|
|
self.setupConfig(config)
|
|
}
|
|
|
|
func (self *IntegrationTest) SetupRepo(shell *Shell) {
|
|
self.setupRepo(shell)
|
|
}
|
|
|
|
func (self *IntegrationTest) Run(gui integrationTypes.GuiDriver) {
|
|
pwd, err := os.Getwd()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
shell := NewShell(pwd, func(errorMsg string) { gui.Fail(errorMsg) })
|
|
keys := gui.Keys()
|
|
testDriver := NewTestDriver(gui, shell, keys, KeyPressDelay())
|
|
|
|
self.run(testDriver, keys)
|
|
|
|
if KeyPressDelay() > 0 {
|
|
// the dev would want to see the final state if they're running in slow mode
|
|
testDriver.Wait(2000)
|
|
}
|
|
}
|
|
|
|
func (self *IntegrationTest) HeadlessDimensions() (int, int) {
|
|
if self.width == 0 && self.height == 0 {
|
|
return defaultWidth, defaultHeight
|
|
}
|
|
|
|
return self.width, self.height
|
|
}
|
|
|
|
func (self *IntegrationTest) RequiresHeadless() bool {
|
|
return self.width != 0 && self.height != 0
|
|
}
|
|
|
|
func testNameFromCurrentFilePath() string {
|
|
path := utils.FilePath(3)
|
|
return TestNameFromFilePath(path)
|
|
}
|
|
|
|
func TestNameFromFilePath(path string) string {
|
|
name := strings.Split(path, "integration/tests/")[1]
|
|
|
|
return name[:len(name)-len(".go")]
|
|
}
|
|
|
|
// this is the delay in milliseconds between keypresses
|
|
// defaults to zero
|
|
func KeyPressDelay() int {
|
|
delayStr := os.Getenv("KEY_PRESS_DELAY")
|
|
if delayStr == "" {
|
|
return 0
|
|
}
|
|
|
|
delay, err := strconv.Atoi(delayStr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return delay
|
|
}
|