summaryrefslogtreecommitdiffstats
path: root/pkg/integration
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-07-17 22:03:51 +1000
committerJesse Duffield <jessedduffield@gmail.com>2023-07-30 18:35:23 +1000
commit277142fc4b9db9d722b648efb29b6fa905b5fb36 (patch)
treedfa1d9a2671ecac37a1339b4d528518bb3fb8676 /pkg/integration
parent18a508b29c82af6e2929860c93b69227ba4ed9c0 (diff)
Add worktree integration tests
Diffstat (limited to 'pkg/integration')
-rw-r--r--pkg/integration/components/shell.go7
-rw-r--r--pkg/integration/components/views.go4
-rw-r--r--pkg/integration/tests/test_list.go5
-rw-r--r--pkg/integration/tests/worktree/add_from_branch.go60
-rw-r--r--pkg/integration/tests/worktree/crud.go120
-rw-r--r--pkg/integration/tests/worktree/rebase.go70
-rw-r--r--pkg/integration/tests/worktree/worktree_in_repo.go85
7 files changed, 351 insertions, 0 deletions
diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go
index decb748da..809cb1d5b 100644
--- a/pkg/integration/components/shell.go
+++ b/pkg/integration/components/shell.go
@@ -254,6 +254,13 @@ func (self *Shell) Init() *Shell {
return self
}
+func (self *Shell) AddWorktree(base string, path string, newBranchName string) *Shell {
+ return self.RunCommand([]string{
+ "git", "worktree", "add", "-b",
+ newBranchName, path, base,
+ })
+}
+
func (self *Shell) MakeExecutable(path string) *Shell {
// 0755 sets the executable permission for owner, and read/execute permissions for group and others
err := os.Chmod(filepath.Join(self.dir, path), 0o755)
diff --git a/pkg/integration/components/views.go b/pkg/integration/components/views.go
index 1a6e54b7e..eb4f585dc 100644
--- a/pkg/integration/components/views.go
+++ b/pkg/integration/components/views.go
@@ -129,6 +129,10 @@ func (self *Views) Files() *ViewDriver {
return self.regularView("files")
}
+func (self *Views) Worktrees() *ViewDriver {
+ return self.regularView("worktrees")
+}
+
func (self *Views) Status() *ViewDriver {
return self.regularView("status")
}
diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go
index 88d1883ac..d2e2848e7 100644
--- a/pkg/integration/tests/test_list.go
+++ b/pkg/integration/tests/test_list.go
@@ -26,6 +26,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/integration/tests/tag"
"github.com/jesseduffield/lazygit/pkg/integration/tests/ui"
"github.com/jesseduffield/lazygit/pkg/integration/tests/undo"
+ "github.com/jesseduffield/lazygit/pkg/integration/tests/worktree"
)
var tests = []*components.IntegrationTest{
@@ -219,4 +220,8 @@ var tests = []*components.IntegrationTest{
ui.SwitchTabFromMenu,
undo.UndoCheckoutAndDrop,
undo.UndoDrop,
+ worktree.AddFromBranch,
+ worktree.Crud,
+ worktree.Rebase,
+ worktree.WorktreeInRepo,
}
diff --git a/pkg/integration/tests/worktree/add_from_branch.go b/pkg/integration/tests/worktree/add_from_branch.go
new file mode 100644
index 000000000..53636536d
--- /dev/null
+++ b/pkg/integration/tests/worktree/add_from_branch.go
@@ -0,0 +1,60 @@
+package worktree
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var AddFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Add a worktree via the branches view, then switch back to the main worktree via the branches view",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupConfig: func(config *config.AppConfig) {},
+ SetupRepo: func(shell *Shell) {
+ shell.NewBranch("mybranch")
+ shell.CreateFileAndAdd("README.md", "hello world")
+ shell.Commit("initial commit")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Focus().
+ Lines(
+ Contains("mybranch"),
+ ).
+ Press(keys.Worktrees.ViewWorktreeOptions).
+ Tap(func() {
+ t.ExpectPopup().Menu().
+ Title(Equals("Worktree")).
+ Select(Contains(`Create worktree from mybranch`).DoesNotContain("detached")).
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New worktree path")).
+ Type("../linked-worktree").
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New branch name")).
+ Type("newbranch").
+ Confirm()
+ }).
+ // confirm we're still focused on the branches view
+ IsFocused().
+ Lines(
+ Contains("newbranch").IsSelected(),
+ Contains("mybranch (worktree)"),
+ ).
+ NavigateToLine(Contains("mybranch")).
+ Press(keys.Universal.Select).
+ Tap(func() {
+ t.ExpectPopup().Confirmation().
+ Title(Equals("Switch to worktree")).
+ Content(Equals("This branch is checked out by worktree repo. Do you want to switch to that worktree?")).
+ Confirm()
+ }).
+ Lines(
+ Contains("mybranch").IsSelected(),
+ Contains("newbranch (worktree)"),
+ )
+ },
+})
diff --git a/pkg/integration/tests/worktree/crud.go b/pkg/integration/tests/worktree/crud.go
new file mode 100644
index 000000000..504d47b72
--- /dev/null
+++ b/pkg/integration/tests/worktree/crud.go
@@ -0,0 +1,120 @@
+package worktree
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var Crud = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "From the worktrees view, add a work tree, switch to it, switch back, and remove it",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupConfig: func(config *config.AppConfig) {},
+ SetupRepo: func(shell *Shell) {
+ shell.NewBranch("mybranch")
+ shell.CreateFileAndAdd("README.md", "hello world")
+ shell.Commit("initial commit")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Lines(
+ Contains("mybranch"),
+ )
+
+ t.Views().Status().
+ Lines(
+ Contains("repo → mybranch"),
+ )
+
+ t.Views().Worktrees().
+ Focus().
+ Lines(
+ Contains("repo (main)"),
+ ).
+ Press(keys.Universal.New).
+ Tap(func() {
+ t.ExpectPopup().Menu().
+ Title(Equals("Worktree")).
+ Select(Contains(`Create worktree from ref`).DoesNotContain(("detached"))).
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New worktree base ref")).
+ InitialText(Equals("mybranch")).
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New worktree path")).
+ Type("../linked-worktree").
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New branch name (leave blank to checkout mybranch)")).
+ Type("newbranch").
+ Confirm()
+ }).
+ Lines(
+ Contains("linked-worktree").IsSelected(),
+ Contains("repo (main)"),
+ ).
+ // confirm we're still in the same view
+ IsFocused()
+
+ // status panel includes the worktree if it's a linked worktree
+ t.Views().Status().
+ Lines(
+ Contains("repo(linked-worktree) → newbranch"),
+ )
+
+ t.Views().Branches().
+ Lines(
+ Contains("newbranch"),
+ Contains("mybranch"),
+ )
+
+ t.Views().Worktrees().
+ // confirm we can't remove the current worktree
+ Press(keys.Universal.Remove).
+ Tap(func() {
+ t.ExpectPopup().Alert().
+ Title(Equals("Error")).
+ Content(Equals("You cannot remove the current worktree!")).
+ Confirm()
+ }).
+ // confirm we cannot remove the main worktree
+ NavigateToLine(Contains("repo (main)")).
+ Press(keys.Universal.Remove).
+ Tap(func() {
+ t.ExpectPopup().Alert().
+ Title(Equals("Error")).
+ Content(Equals("You cannot remove the main worktree!")).
+ Confirm()
+ }).
+ // switch back to main worktree
+ Press(keys.Universal.Select).
+ Lines(
+ Contains("repo (main)").IsSelected(),
+ Contains("linked-worktree"),
+ )
+
+ t.Views().Branches().
+ Lines(
+ Contains("mybranch"),
+ Contains("newbranch"),
+ )
+
+ t.Views().Worktrees().
+ // remove linked worktree
+ NavigateToLine(Contains("linked-worktree")).
+ Press(keys.Universal.Remove).
+ Tap(func() {
+ t.ExpectPopup().Confirmation().
+ Title(Equals("Remove worktree")).
+ Content(Contains("Are you sure you want to remove worktree 'linked-worktree'?")).
+ Confirm()
+ }).
+ Lines(
+ Contains("repo (main)").IsSelected(),
+ )
+ },
+})
diff --git a/pkg/integration/tests/worktree/rebase.go b/pkg/integration/tests/worktree/rebase.go
new file mode 100644
index 000000000..e8ae59556
--- /dev/null
+++ b/pkg/integration/tests/worktree/rebase.go
@@ -0,0 +1,70 @@
+package worktree
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+// This is important because `git worktree list` will show a worktree being in a detached head state (which is true)
+// when it's in the middle of a rebase, but it won't tell you about the branch it's on.
+// Even so, if you attempt to check out that branch from another worktree git won't let you, so we need to
+// keep track of the association ourselves.
+
+var Rebase = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Verify that when you start a rebase in a worktree, Lazygit still associates the worktree with the branch",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupConfig: func(config *config.AppConfig) {},
+ SetupRepo: func(shell *Shell) {
+ shell.NewBranch("mybranch")
+ shell.CreateFileAndAdd("README.md", "hello world")
+ shell.Commit("initial commit")
+ shell.EmptyCommit("commit 2")
+ shell.EmptyCommit("commit 3")
+ shell.AddWorktree("mybranch", "../linked-worktree", "newbranch")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Focus().
+ Lines(
+ Contains("mybranch"),
+ Contains("newbranch (worktree)"),
+ )
+
+ t.Views().Commits().
+ Focus().
+ NavigateToLine(Contains("commit 2")).
+ Press(keys.Universal.Edit)
+
+ t.Views().Information().Content(Contains("Rebasing"))
+
+ t.Views().Branches().
+ Focus().
+ // switch to linked worktree
+ NavigateToLine(Contains("newbranch")).
+ Press(keys.Universal.Select).
+ Tap(func() {
+ t.ExpectPopup().Confirmation().
+ Title(Equals("Switch to worktree")).
+ Content(Equals("This branch is checked out by worktree linked-worktree. Do you want to switch to that worktree?")).
+ Confirm()
+
+ t.Views().Information().Content(DoesNotContain("Rebasing"))
+ }).
+ Lines(
+ Contains("newbranch").IsSelected(),
+ Contains("mybranch (worktree)"),
+ ).
+ // switch back to main worktree
+ NavigateToLine(Contains("mybranch")).
+ Press(keys.Universal.Select).
+ Tap(func() {
+ t.ExpectPopup().Confirmation().
+ Title(Equals("Switch to worktree")).
+ Content(Equals("This branch is checked out by worktree repo. Do you want to switch to that worktree?")).
+ Confirm()
+
+ t.Views().Information().Content(Contains("Rebasing"))
+ })
+ },
+})
diff --git a/pkg/integration/tests/worktree/worktree_in_repo.go b/pkg/integration/tests/worktree/worktree_in_repo.go
new file mode 100644
index 000000000..743abddf5
--- /dev/null
+++ b/pkg/integration/tests/worktree/worktree_in_repo.go
@@ -0,0 +1,85 @@
+package worktree
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var WorktreeInRepo = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Add a worktree inside the repo, then remove the directory and confirm the worktree is removed",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupConfig: func(config *config.AppConfig) {},
+ SetupRepo: func(shell *Shell) {
+ shell.NewBranch("mybranch")
+ shell.CreateFileAndAdd("README.md", "hello world")
+ shell.Commit("initial commit")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Lines(
+ Contains("mybranch"),
+ )
+
+ t.Views().Worktrees().
+ Focus().
+ Lines(
+ Contains("repo (main)"),
+ ).
+ Press(keys.Universal.New).
+ Tap(func() {
+ t.ExpectPopup().Menu().
+ Title(Equals("Worktree")).
+ Select(Contains(`Create worktree from ref`).DoesNotContain(("detached"))).
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New worktree base ref")).
+ InitialText(Equals("mybranch")).
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New worktree path")).
+ Type("linked-worktree").
+ Confirm()
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("New branch name (leave blank to checkout mybranch)")).
+ Type("newbranch").
+ Confirm()
+ }).
+ Lines(
+ Contains("linked-worktree").IsSelected(),
+ Contains("repo (main)"),
+ ).
+ // switch back to main worktree
+ NavigateToLine(Contains("repo (main)")).
+ Press(keys.Universal.Select).
+ Lines(
+ Contains("repo (main)").IsSelected(),
+ Contains("linked-worktree"),
+ )
+
+ t.Views().Files().
+ Focus().
+ Lines(
+ Contains("linked-worktree"),
+ ).
+ Press(keys.Universal.Remove).
+ Tap(func() {
+ t.ExpectPopup().Menu().
+ Title(Equals("linked-worktree")).
+ Select(Contains("Discard all changes")).
+ Confirm()
+ }).
+ IsEmpty()
+
+ // confirm worktree appears as missing
+ t.Views().Worktrees().
+ Focus().
+ Lines(
+ Contains("repo (main)").IsSelected(),
+ Contains("linked-worktree (missing)"),
+ )
+ },
+})