main_view

package
v0.66.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AdvanceAfterStagingShiftsLineNumbers = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Staging a hunk that adds a line still leaves the selection on the next hunk, whose line numbers it moved",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "1\nX\n3\n4\nNEW\n5\n6\nY\n8\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-2"),
				Contains("+X"),
			).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("+NEW"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("-7"),
				Contains("+Y"),
			)
	},
})
View Source
var ApplyCustomPatch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Apply a custom patch built from a branch commit's focused diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	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(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Branches().
			Focus().
			Lines(
				Contains("branch-a").IsSelected(),
				Contains("branch-b"),
			).
			Press(keys.Universal.NextItem).
			PressEnter()

		t.Views().SubCommits().
			IsFocused().
			Lines(
				Contains("update").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("M file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+second line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("second line"))
		t.Common().SelectPatchOption(MatchesRegexp(`Apply patch$`))

		t.Views().Files().
			Focus().
			Lines(
				Contains("file1").IsSelected(),
			)
		t.Views().Secondary().Content(Contains("second line"))
	},
})
View Source
var ApplyCustomPatchInReverse = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Apply a custom patch built from a focused commit diff in reverse",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content\n")
		shell.CreateFileAndAdd("file2", "file2 content\n")
		shell.Commit("first commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("first commit").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  A file1"),
				Equals("  A file2"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("+file1 content"))
		t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

		t.Views().Files().
			Focus().
			Lines(
				Contains("D").Contains("file1").IsSelected(),
			)
		t.Views().Secondary().Content(Contains("-file1 content"))
	},
})
View Source
var ApplyCustomPatchInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Apply a multi-file custom patch in reverse when one file conflicts",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content\n")
		shell.CreateFileAndAdd("file2", "file2 content\n")
		shell.Commit("first commit")
		shell.UpdateFileAndAdd("file1", "file1 content\nmore file1 content\n")
		shell.UpdateFileAndAdd("file2", "file2 content\nmore file2 content\n")
		shell.Commit("second commit")
		shell.UpdateFileAndAdd("file1", "file1 content\nmore file1 content\neven more file1\n")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("second commit"),
				Contains("first commit"),
			).
			NavigateToLine(Contains("second commit")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  M file1"),
				Equals("  M file2"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+more file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+more file2 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("+more file1 content").Contains("+more file2 content"))
		t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("Applied patch to 'file1' with conflicts.")).
			Confirm()

		t.Views().Files().
			Focus().
			Lines(
				Equals("UU file1").IsSelected(),
			).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			ContainsLines(
				Contains("file1 content"),
				Contains("<<<<<<< ours").IsSelected(),
				Contains("more file1 content").IsSelected(),
				Contains("even more file1").IsSelected(),
				Contains("=======").IsSelected(),
				Contains(">>>>>>> theirs"),
			).
			SelectNextItem().
			PressPrimaryAction()

		t.Views().Files().
			Focus().
			Lines(
				Equals("▼ /"),
				Equals("  M  file1").IsSelected(),
				Equals("  M  file2"),
			)
		t.Views().Secondary().ContainsLines(
			Contains(" file1 content"),
			Contains("-more file1 content"),
			Contains("-even more file1"),
		)
	},
})
View Source
var ApplyCustomPatchWithModifiedFile = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Apply a custom patch alongside a non-conflicting working-tree change",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.NewBranch("branch-a")
		shell.CreateFileAndAdd("file1", "1\n2\n3\n")
		shell.Commit("first commit")

		shell.NewBranch("branch-b")
		shell.UpdateFileAndAdd("file1", "1\n2\n3\n4\n")
		shell.Commit("update")

		shell.Checkout("branch-a")
		shell.UpdateFile("file1", "11\n2\n3\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Branches().
			Focus().
			Lines(
				Contains("branch-a").IsSelected(),
				Contains("branch-b"),
			).
			Press(keys.Universal.NextItem).
			PressEnter()

		t.Views().SubCommits().
			IsFocused().
			Lines(
				Contains("update").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("M file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+4")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("3\n+4"))
		t.Common().SelectPatchOption(MatchesRegexp(`Apply patch$`))

		t.ExpectPopup().Confirmation().Title(Equals("Must stage files")).
			Content(Contains("Applying a patch to the index requires staging the unstaged files that are affected by the patch.")).
			Confirm()

		t.Views().Files().
			Focus().
			Lines(
				Equals("M  file1").IsSelected(),
			)
		t.Views().Secondary().Content(Contains("-1\n+11\n 2\n 3\n+4"))
	},
})
View Source
var ApplyCustomPatchWithModifiedFileConflict = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Apply a custom patch that conflicts with a working-tree change",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.NewBranch("branch-a")
		shell.CreateFileAndAdd("file1", "1\n2\n3\n")
		shell.Commit("first commit")

		shell.NewBranch("branch-b")
		shell.UpdateFileAndAdd("file1", "11\n2\n3\n")
		shell.Commit("update")

		shell.Checkout("branch-a")
		shell.UpdateFile("file1", "111\n2\n3\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Branches().
			Focus().
			Lines(
				Contains("branch-a").IsSelected(),
				Contains("branch-b"),
			).
			Press(keys.Universal.NextItem).
			PressEnter()

		t.Views().SubCommits().
			IsFocused().
			Lines(
				Contains("update").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("M file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-1")).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("-1\n+11\n"))
		t.Common().SelectPatchOption(MatchesRegexp(`Apply patch$`))

		t.ExpectPopup().Confirmation().Title(Equals("Must stage files")).
			Content(Contains("Applying a patch to the index requires staging the unstaged files that are affected by the patch.")).
			Confirm()

		t.ExpectPopup().Alert().Title(Equals("Error")).
			Content(Contains("Applied patch to 'file1' with conflicts.")).
			Confirm()

		t.Views().Files().
			Focus().
			Lines(
				Equals("UU file1").IsSelected(),
			).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			Lines(
				Equals("<<<<<<< ours"),
				Equals("111"),
				Equals("======="),
				Equals("11"),
				Equals(">>>>>>> theirs"),
				Equals("2"),
				Equals("3"),
			)
	},
})
View Source
var BuildPatchFromACommitsDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Take lines of a commit's diff into a custom patch, and back out of it, from the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "ONE\ntwo\nTHREE\nfour\nfive\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-one"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("+ONE"),
			)

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().ContainsLines(
			Contains("-one"),
			Contains(" two"),
		)

		t.Views().Main().MarkedLines(
			Contains("-one"),
		)

		t.Views().Main().
			IsFocused().
			PressPrimaryAction().
			SelectedLines(
				Contains("-three"),
			)

		t.Views().Secondary().ContainsLines(
			Contains("-one"),
			Contains("+ONE"),
			Contains(" two"),
		)
		t.Views().Main().MarkedLines(
			Contains("-one"),
			Contains("+ONE"),
		)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+ONE")).
			PressPrimaryAction()

		t.Views().Secondary().
			ContainsLines(
				Contains("-one"),
				Contains(" two"),
			).
			Content(DoesNotContain("+ONE"))
		t.Views().Main().MarkedLines(
			Contains("-one"),
		)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("-one")).
			PressPrimaryAction()

		t.Views().Information().Content(DoesNotContain("Building patch"))
		t.Views().Main().NoMarkedLines()
	},
})
View Source
var BuildPatchFromAReflogEntry = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Take lines of the diff of a reflog entry into a custom patch, which can then be applied",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().ReflogCommits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().ContainsLines(
			Contains("-two"),
			Contains(" three"),
		)

		t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

		t.Views().Files().
			Focus().
			Lines(
				Contains("M").Contains("file1"),
			)
	},
})
View Source
var BuildPatchFromAWholeCommitsDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Take lines of two files into a custom patch from the whole diff of a commit, without entering its files first",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.CreateFileAndAdd("file2", "alpha\nbeta\ngamma\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.UpdateFileAndAdd("file2", "alpha\nBETA\ngamma\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("-beta"),
				Contains("+BETA"),
			).
			PressPrimaryAction()

		t.Views().Secondary().
			Content(Contains("file1")).
			Content(Contains("file2")).
			ContainsLines(
				Contains("-two"),
				Contains("+TWO"),
				Contains(" three"),
			).
			ContainsLines(
				Contains("-beta"),
				Contains("+BETA"),
				Contains(" gamma"),
			)

		t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

		t.Views().Files().
			Focus().
			ContainsLines(
				Contains("M").Contains("file1"),
				Contains("M").Contains("file2"),
			)
	},
})
View Source
var BuildPatchWithMixedSelections = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Build a custom patch from a whole file, a hunk, individual lines, and a range",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("hunk-file", "1a\n1b\n1c\n1d\n1e\n1f\n1g\n1h\n1i\n1j\n1k\n1l\n1m\n1n\n1o\n1p\n1q\n1r\n1s\n1t\n1u\n1v\n1w\n1x\n1y\n1z\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("hunk-file", "aa\n1b\ncc\n1d\n1e\n1f\n1g\n1h\n1i\n1j\n1k\n1l\n1m\n1n\n1o\n1p\n1q\n1r\n1s\ntt\nuu\nvv\n1w\n1x\n1y\n1z\n")
		shell.CreateFileAndAdd("line-file", "2a\n2b\n2c\n2d\n2e\n2f\n2g\n2h\n2i\n2j\n2k\n2l\n2m\n2n\n2o\n2p\n2q\n2r\n2s\n2t\n2u\n2v\n2w\n2x\n2y\n2z\n")
		shell.CreateFileAndAdd("direct-file", "direct file content")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Contains("direct-file"),
				Contains("hunk-file"),
				Contains("line-file"),
			).
			SelectNextItem().
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("direct file content"))

		t.Views().CommitFiles().
			NavigateToLine(Contains("hunk-file")).
			Press(keys.Universal.FocusMainView)
		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-1a")).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-1a"),
				Contains("+aa"),
			).
			PressPrimaryAction().
			PressEscape().
			PressEscape()

		t.Views().CommitFiles().
			IsFocused().
			NavigateToLine(Contains("line-file")).
			Press(keys.Universal.FocusMainView)
		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+2a")).
			PressPrimaryAction().
			NavigateToLine(Contains("+2c")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+2e")).
			PressPrimaryAction().
			NavigateToLine(Contains("+2g")).
			PressPrimaryAction().
			PressEscape()

		t.Views().Secondary().ContainsLines(

			Contains(`diff --git a/direct-file b/direct-file`),
			Contains(`index`),
			Contains(`--- a/direct-file`),
			Contains(`+++ b/direct-file`),
			Contains(`@@ -0,0 +1 @@`),
			Contains(`+direct file content`),
			Contains(`\ No newline at end of file`),

			Contains(`diff --git a/hunk-file b/hunk-file`),
			Contains(`index`),
			Contains(`--- a/hunk-file`),
			Contains(`+++ b/hunk-file`),
			Contains(`@@ -1,4 +1,4 @@`),
			Contains(`-1a`),
			Contains(`+aa`),
			Contains(` 1b`),
			Contains(` 1c`),
			Contains(` 1d`),

			Contains(`diff --git a/line-file b/line-file`),
			Contains(`index`),
			Contains(`--- a/line-file`),
			Contains(`+++ b/line-file`),
			Contains(`@@ -0,0 +1,5 @@`),
			Contains(`+2a`),
			Contains(`+2c`),
			Contains(`+2d`),
			Contains(`+2e`),
			Contains(`+2g`),
		)
	},
})
View Source
var ChangeContextSizeWhileBuildingPatch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Change diff context size while building a custom patch, then add another line",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
		config.GetUserConfig().Git.DiffContextSize = 1
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("first commit")
		shell.UpdateFileAndAdd("file1", "ONE\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nTEN\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-one")).
			PressPrimaryAction().
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			NavigateToLine(Contains("-ten")).
			PressPrimaryAction()

		t.Views().Secondary().Content(
			Contains("-one").Contains("-ten"),
		)
		t.Views().Main().MarkedLines(
			Contains("-one"),
			Contains("-ten"),
		)
	},
})
View Source
var ChangeScreenModeInFocusedDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Enlarge the focused diff, which leaves the pane showing the other side of the file behind",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFile("file", "first line\nsecond line")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressPrimaryAction().
			Title(Equals("Unstaged changes")).
			Content(Contains("+second line").DoesNotContain("+first line")).
			PressTab()

		t.Views().Secondary().
			IsFocused().
			Title(Equals("Staged changes")).
			Content(Contains("+first line").DoesNotContain("+second line")).
			Press(keys.Universal.NextScreenMode).
			Tap(func() {

				t.Views().AppStatus().IsInvisible()
				t.Views().Main().IsVisible()
			}).
			Press(keys.Universal.NextScreenMode).
			Tap(func() {

				t.Views().AppStatus().IsInvisible()
				t.Views().Main().IsInvisible()
			})
	},
})
View Source
var ClickAFileInADiffStatThatComesFirst = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Jump to a file by clicking its name in a diffstat the renderer's handshake runs into",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        100,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Command: `printf '\033]1717;1\007'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("aaa.txt", "one\n")
		shell.Commit("one")
		shell.CreateFileAndAdd("zzz.txt", "one\n")
		shell.Commit("two")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			SelectedLine(Contains("two")).
			Press(keys.Universal.ToggleRangeSelect).
			SelectNextItem().
			SelectedLines(
				Contains("two"),
				Contains("one"),
			)

		t.Views().Main().
			TopLines(
				Contains("Showing diff for range"),
				Equals(""),
				Contains("aaa.txt"),
				Contains("zzz.txt"),
				Contains("2 files changed"),
			).
			Click(2, 2)

		t.Views().Commits().IsFocused()

		t.Views().Main().
			TopVisibleLine(Contains("diff --git a/aaa.txt b/aaa.txt"))
	},
})
View Source
var ClickAFileInTheDiffStat = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Jump to a file of a commit's diff by clicking the line that names it in the diffstat",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        100,
	Height:       30,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 600)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%03d", i+1)
		}

		shell.CreateFileAndAdd("aaa.txt", strings.Join(lines, "\n")+"\n")
		shell.CreateFileAndAdd("dir/bbb.txt", "one\n")
		shell.CreateFileAndAdd("zzz.txt", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			SelectedLine(Contains("one"))

		t.Views().Main().
			TopLines(
				Contains("commit"),
				Contains("Author:"),
				Contains("Date:"),
				Equals(""),
				Contains("one"),
				Equals("---"),
				Contains("aaa.txt"),
				Contains("dir/bbb.txt"),
				Contains("zzz.txt"),
				Contains("3 files changed"),
			).
			Click(2, 8)

		t.Views().Commits().
			IsFocused().
			SelectedLine(Contains("one"))

		t.Views().Main().
			TopVisibleLine(Contains("diff --git a/zzz.txt b/zzz.txt"))

		t.Views().Commits().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Universal.GotoTop)

		t.Views().Main().
			TopVisibleLine(Contains("commit")).
			Click(2, 6).
			SelectedLines(
				Contains("diff --git a/aaa.txt b/aaa.txt"),
			).
			TopVisibleLine(Contains("commit")).
			Click(2, 8).
			SelectedLines(
				Contains("diff --git a/zzz.txt b/zzz.txt"),
			).
			TopVisibleLine(Contains("diff --git a/zzz.txt b/zzz.txt"))
	},
})
View Source
var ClickSelectsDiffLine = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Clicking a line of the main view's diff focuses the view and selects that line",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused()

		t.Views().Main().
			Click(0, 4).
			IsFocused().
			SelectionIsActive().
			SelectedLines(
				Contains("@@ -1,5 +1,5 @@"),
			).
			Click(0, 7).
			SelectedLines(
				Contains("-three"),
			)
	},
})
View Source
var CommitFromMainView = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Commit what you staged without leaving the focused main view, but not while looking at a commit's diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nADDED\ntwo\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Files.CommitChanges).
			IsFocused()

		t.Views().Files().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+ADDED"),
			).
			PressPrimaryAction()

		t.Views().Secondary().
			IsFocused().
			Press(keys.Files.CommitChanges)

		t.ExpectPopup().CommitMessagePanel().
			Type("staged from the diff").
			Confirm()

		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Content(Contains("No changed files"))

		t.Views().Commits().Lines(
			Contains("staged from the diff"),
			Contains("one"),
		)
	},
})
View Source
var CopyRowsThatAreNoDiffLine = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Copying rows that stand for no line of the diff says so rather than copying nothing",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
		cfg.GetUserConfig().OS.CopyToClipboardCmd = "printf '%s' {{text}} > clipboard"

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Command: `printf '\033]1717;1\007'; ` +
				`printf '\033]1717;1;f;;;file1\007file1\n'; ` +
				`printf '\033]1717;1;c;1;;file1\007 one\n'; ` +
				`printf '\033]1717;1;d;2;2;file1\007-two\n'; ` +
				`printf '\033]1717;1;a;2;;file1\007+TWO\n'; ` +
				`printf '\033]1717;1;c;3;;file1\007 three\n'; ` +
				`printf -- '--- that was the diff ---\n'; ` +
				`cat >/dev/null`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			SelectNextItem().
			SelectNextItem().
			SelectNextItem().
			SelectedLines(
				Contains("that was the diff"),
			).
			Press(keys.Universal.CopyToClipboard)

		t.ExpectToast(Equals("Nothing in the selection could be found in the diff"))
		t.FileSystem().PathNotPresent("clipboard")
	},
})
View Source
var CopySelectedDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Copy the selected diff lines from the focused main view, as the diff reads rather than as the renderer drew it",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true

		cfg.GetUserConfig().OS.CopyToClipboardCmd = "printf '%s' {{text}} > clipboard"

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{
				Command: `printf '\033]1717;1\007'; ` +
					`awk '/^@@/ { body = 1 } body && /^[-+ ]/ { print $0 " <<<"; next } { print }'`,
				ColorArg: "never",
			},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")
		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("two")

		shell.UpdateFile("file1", "one\nTWO\nADD1\nADD2\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+ADD1 <<<"),
				Contains("+ADD2 <<<"),
			).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, Equals("ADD1\nADD2\n"))

		t.Views().Main().
			IsFocused().
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("+ADD1 <<<"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.PrevItem).
			Press(keys.Universal.PrevItem).
			Press(keys.Universal.PrevItem).
			SelectedLines(
				Contains("@@ -1,3 +1,5 @@"),
				Contains(" one <<<"),
				Contains(" TWO <<<"),
				Contains("+ADD1 <<<"),
			).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, Equals("@@ -1,3 +1,5 @@\n one\n TWO\n+ADD1\n"))

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.PrevItem).
			SelectedLines(
				Contains("+++ b/file1"),
				Contains("@@ -1,3 +1,5 @@"),
				Contains(" one <<<"),
				Contains(" TWO <<<"),
				Contains("+ADD1 <<<"),
			).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, MatchesRegexp(
			`\Adiff --git a/file1 b/file1\nindex [0-9a-f]+\.\.[0-9a-f]+ 100644\n`+
				`--- a/file1\n\+\+\+ b/file1\n@@ -1,3 \+1,5 @@\n one\n TWO\n\+ADD1\n\z`))

		t.Views().Commits().
			Focus().
			NavigateToLine(Contains("two")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two <<<"),
				Contains("+TWO <<<"),
			).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, Equals("-two\n+TWO\n"))

		t.Views().Main().
			IsFocused().
			Press(keys.Main.ToggleSelectHunk).
			NavigateToLine(Contains("    two")).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, Equals("    two\n"))

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("-two <<<")).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, MatchesRegexp(
			`\A {4}two\n---\n file1 \|[^\n]*\n 1 file changed[^\n]*\n\n`+
				`diff --git a/file1 b/file1\nindex [0-9a-f]+\.\.[0-9a-f]+ 100644\n`+
				`--- a/file1\n\+\+\+ b/file1\n@@ -1,3 \+1,3 @@\n one\n-two\n\z`))

		t.Views().Main().
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-two <<<"),
				Contains("+TWO <<<"),
			).
			PressPrimaryAction().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("-two <<<"),
				Contains("+TWO <<<"),
			).
			Press(keys.Universal.CopyToClipboard)

		expectClipboard(t, Equals("-two\n+TWO\n"))
	},
})
View Source
var CustomPatchGoesThroughTheDiffRenderer = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The custom patch is shown by the configured diff renderer, being rendered as a diff of real files rather than assembled by us",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Command: `printf '\033]1717;1\007RENDERED BY ME\n'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("RENDERED BY ME")).
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction()

		t.Views().Secondary().
			Content(Contains("RENDERED BY ME")).
			ContainsLines(
				Contains(" one"),
				Contains("-two"),
				Contains(" three"),
			)
	},
})
View Source
var CustomPatchIgnoresLineEndingConversion = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The custom patch is shown as git states it on a machine that checks files out with CRLF",
	ExtraCmdArgs: []string{},
	Skip:         false,

	ExtraEnvVars: map[string]string{
		"GIT_CONFIG_COUNT":   "1",
		"GIT_CONFIG_KEY_0":   "core.autocrlf",
		"GIT_CONFIG_VALUE_0": "true",
	},
	SetupConfig: func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction()

		t.Views().Secondary().
			ContainsLines(
				Contains(" one"),
				Contains("-two"),
				Contains(" three"),
			).
			Content(DoesNotContain("warning"))
	},
})
View Source
var DiscardAllChanges = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Discard all changes of a file from the focused main view, then land on the next file's diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\n")
		shell.CreateFileAndAdd("file2", "1\n2\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nthree\nfour\n")
		shell.UpdateFile("file2", "1\n2\n3\n4\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("   M file1"),
				Equals("   M file2"),
			).
			SelectNextItem().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+three")).
			Press(keys.Universal.Remove).
			Tap(func() {
				t.Common().ConfirmDiscardLines()
			}).
			SelectedLines(Contains("+four")).
			Press(keys.Universal.Remove).
			Tap(func() {
				t.Common().ConfirmDiscardLines()
			})

		t.Views().Files().Lines(
			Equals(" M file2"),
		)
		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+3"))
	},
})
View Source
var DiscardDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Discard a hunk of the working tree's diff from the focused main view, and unstage one from the staged half",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.UpdateFile("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\nUNSTAGED\neight\nnine\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("MM file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+UNSTAGED"),
			).
			Press(keys.Universal.Remove).
			Tap(func() {
				t.ExpectPopup().Confirmation().
					Title(Equals("Discard change")).
					Content(Contains("Are you sure you want to discard this change")).
					Confirm()
			})

		t.Views().Files().Lines(
			Contains("M  file1"),
		)
		t.Views().Main().IsInvisible()

		t.Views().Secondary().
			IsFocused().
			Title(Equals("Staged changes")).
			SelectedLines(
				Contains("+STAGED"),
			).
			Press(keys.Universal.Remove)

		t.Views().Files().Lines(
			Contains(" M file1"),
		)
		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Title(Equals("Unstaged changes")).
			Content(Contains("+STAGED"))
	},
})
View Source
var DiscardFromACommitOnlyWhereItCanBeRewritten = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Discarding lines is refused over a diff that belongs to no commit we may rewrite, and over the custom patch itself",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFile("file1", "one\nTWO\nthree\n")
		shell.Stash("a stashed change")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Stash().
			Focus().
			Lines(
				Contains("a stashed change").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Universal.Remove)

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("Changes can only be discarded from local commits")).
			Confirm()

		t.Views().Main().
			IsFocused().
			PressPrimaryAction().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Universal.Remove)

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("Lines shown here are the custom patch's")).
			Confirm()
	},
})
View Source
var DiscardLineFromAddedFileInCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Discard one line from an added file in a commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("first commit")
		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("commit to remove from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to remove from").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+2nd line")).
			Press(keys.Universal.Remove)

		t.ExpectPopup().Confirmation().
			Title(Equals("Discard lines from commit")).
			Content(Equals("Are you sure you want to discard the selected lines from this commit?")).
			Confirm()

		t.Views().Main().
			IsFocused().
			ContainsLines(
				Equals("+1st line"),
				Equals("+3rd line"),
			)
	},
})
View Source
var DiscardLinesFromACommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Discard the selected lines of a commit's diff from the commit itself, in the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\nFOUR\nfive\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+TWO")).
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			Press(keys.Universal.Remove)

		t.ExpectPopup().Confirmation().
			Title(Equals("Discard lines from commit")).
			Content(Contains("Are you sure you want to discard the selected lines from this commit?")).
			Confirm()

		t.Views().Main().
			IsFocused().
			Content(DoesNotContain("+TWO")).
			SelectedLines(
				Contains("-four"),
			)

		t.Views().Files().IsEmpty()
	},
})
View Source
var DragRangeWithAutoscroll = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Keep scrolling while dragging a range selection at the edge of the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		fileContent := "base\n"
		shell.CreateFileAndAdd("file1", fileContent)
		shell.Commit("one")
		for i := 1; i <= 40; i++ {
			fileContent += fmt.Sprintf("line %d\n", i)
		}
		shell.UpdateFile("file1", fileContent)
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			ClickAndHold(1, 6).
			MouseMoveToBottom(1).
			OriginYAtLeast(3).
			SelectedLineIdxAtLeast(9).
			MouseRelease()
	},
})
View Source
var DragSelectsDiffLineRange = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Dragging in the main view's diff selects the range from the line the drag started on",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nFOUR\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-three"),
				Contains("-four"),
				Contains("+THREE"),
				Contains("+FOUR"),
			).
			ClickAndHold(0, 8).
			MouseMove(0, 9).
			SelectedLines(
				Contains("-four"),
				Contains("+THREE"),
			).
			MouseMove(0, 10).
			SelectedLines(
				Contains("-four"),
				Contains("+THREE"),
				Contains("+FOUR"),
			).
			MouseRelease().
			SelectedLines(
				Contains("-four"),
				Contains("+THREE"),
				Contains("+FOUR"),
			)
	},
})
View Source
var EditClickedDiffLine = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Alt- or shift-click a line of the main view's diff to open it in the editor, without focusing the view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
		config.GetUserConfig().OS.EditAtLine = "echo {{filename}}:{{line}} > edit-command"
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused()

		t.Views().Main().
			AltClick(0, 8).
			Tap(func() {
				t.FileSystem().FileContent("edit-command", Contains("/repo/file1:3\n"))
			}).
			SelectionIsHidden()

		t.Views().Files().
			IsFocused()

		t.Views().Main().
			ShiftClick(0, 9).
			Tap(func() {
				t.FileSystem().FileContent("edit-command", Contains("/repo/file1:4\n"))
			})

		t.Views().Files().
			Press(keys.Universal.Remove)

		t.Views().Menu().
			IsFocused()

		t.Views().Main().
			AltClick(0, 6).
			Tap(func() {
				t.FileSystem().FileContent("edit-command", Contains("/repo/file1:2\n"))
			})

		t.Views().Menu().
			IsFocused().
			Press(keys.Universal.Return)
	},
})
View Source
var EditHistoricalDiffLine = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Edit a historical diff line at its current working-tree line number",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
		config.GetUserConfig().OS.EditAtLine = "echo {{filename}}:{{line}} > edit-command"
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file.txt", "4\n5\n6\n")
		shell.Commit("01")
		shell.UpdateFileAndAdd("file.txt", "1\n2a\n2b\n3\n4\n5\n6\n")
		shell.Commit("02")
		shell.UpdateFile("file.txt", "1\n2\n3\n4\n5\n6\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("02").IsSelected(),
				Contains("01"),
			).
			Press(keys.Universal.NextItem).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file.txt").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("+4\n+5\n+6")).
			NavigateToLine(Contains("+5")).
			Press(keys.Universal.Edit)

		t.FileSystem().FileContent("edit-command", Contains("file.txt:5\n"))
	},
})
View Source
var EditHunkInFocusedDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Edit the hunk around the selection in an editor, and stage what comes back",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().OS.EditAtLineAndWait = "echo {{line}} > ../edit-line && " +
			"printf '%s\\n' '--- a/file1' '+++ b/file1' '@@ -1,3 +1,3 @@' " +
			"' one' '-two' '+TWO_EDITED' ' three' > {{filename}}"
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-two")).
			Press(keys.Main.EditSelectHunk)

		t.FileSystem().FileContent("../edit-line", Equals("5\n"))

		t.Views().Files().Lines(
			Contains("MM").Contains("file1"),
		)
		t.Views().Secondary().ContainsLines(
			Contains("-two"),
			Contains("+TWO_EDITED"),
		)
		t.Views().Main().ContainsLines(
			Contains("-TWO_EDITED"),
			Contains("+TWO"),
		)
	},
})
View Source
var EditSelectedDiffLine = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Open the selected line of the main view's diff in the editor, at that line of the file",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
		config.GetUserConfig().OS.EditAtLine = "echo {{filename}}:{{line}} > edit-command"
		config.GetUserConfig().OS.Edit = "echo {{filename}} > edit-command"
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+THREE")).
			Press(keys.Universal.Edit)

		t.FileSystem().FileContent("edit-command", Contains("/repo/file1:3\n"))

		t.Views().Main().
			NavigateToLine(Contains("diff --git a/file1 b/file1")).
			Press(keys.Universal.Edit)

		t.FileSystem().FileContent("edit-command", Contains("/repo/file1\n"))
	},
})
View Source
var EnterAndDoubleClickFocusFileDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Enter and double-click focus a file's diff in the main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "base\n")
		shell.Commit("add file")
		shell.UpdateFile("file1", "changed\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			PressEnter()

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-base")).
			PressEscape()

		t.Views().Files().
			IsFocused().
			Click(3, 0).
			Click(3, 0)
		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-base")).
			PressEscape()

		t.Views().Commits().
			Focus().
			Lines(
				Contains("add file").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			PressEnter()

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+base")).
			PressEscape()

		t.Views().CommitFiles().
			IsFocused().
			Click(3, 0).
			Click(3, 0)
		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+base"))
	},
})
View Source
var EscapeDismissesSelection = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Escape gives up a range selection, then hunk mode, before leaving the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nTHREE\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-two"),
				Contains("-three"),
			).
			Press(keys.Universal.Return).
			IsFocused().
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-two"),
				Contains("-three"),
				Contains("+TWO"),
				Contains("+THREE"),
			).
			Press(keys.Universal.Return).
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Universal.Return)

		t.Views().Files().
			IsFocused()
	},
})
View Source
var FileNavigationScrollsToTheTop = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Going to a file of a diff brings it to the top of the view, unless it is on screen already",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        100,
	Height:       20,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false

		config.GetUserConfig().Git.DiffContextSize = 30
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 100)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%03d", i+1)
		}
		long := strings.Join(lines, "\n") + "\n"
		longChanged := strings.Replace(long, "line100", "LINE100", 1)

		shell.CreateFileAndAdd("aaa.txt", long)
		shell.CreateFileAndAdd("bbb.txt", "one\ntwo\nthree\n")
		shell.CreateFileAndAdd("ccc.txt", "one\ntwo\nthree\n")
		shell.CreateFileAndAdd("ddd.txt", long)
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("aaa.txt", longChanged)
		shell.UpdateFileAndAdd("bbb.txt", "one\nTWO\nthree\n")
		shell.UpdateFileAndAdd("ccc.txt", "one\nTWO\nthree\n")
		shell.UpdateFileAndAdd("ddd.txt", longChanged)
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Main.NextFile).
			TopVisibleLine(Contains("diff --git a/bbb.txt b/bbb.txt")).
			SelectedLines(
				Contains("diff --git a/bbb.txt b/bbb.txt"),
			).
			Press(keys.Main.NextFile).
			TopVisibleLine(Contains("diff --git a/bbb.txt b/bbb.txt")).
			SelectedLines(
				Contains("diff --git a/ccc.txt b/ccc.txt"),
			).
			Press(keys.Main.PrevFile).
			Press(keys.Main.PrevFile).
			TopVisibleLine(Contains("diff --git a/aaa.txt b/aaa.txt")).
			SelectedLines(
				Contains("diff --git a/aaa.txt b/aaa.txt"),
			).
			Press(keys.Main.ToggleSelectHunk).
			Press(keys.Main.NextFile).
			Press(keys.Main.NextFile).
			Press(keys.Main.NextFile).
			SelectedLines(
				Contains("-line100"),
				Contains("+LINE100"),
			).
			SelectedLineIsVisible()
	},
})
View Source
var FocusFollowsAPaneEmptiedFromOutside = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Committing the staged changes outside lazygit takes the staged pane away, so the focus follows into the one that is left",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\n")
		shell.UpdateFile("file1", "one\nSTAGED\ntwo\nthree\nUNSTAGED\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			Title(Equals("Staged changes")).
			SelectedLines(
				Contains("+STAGED"),
			)

		t.Shell().Commit("two")
		t.GlobalPress(keys.Universal.Refresh)

		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Title(Equals("Unstaged changes")).
			SelectedLines(
				Contains("+UNSTAGED"),
			)
	},
})
View Source
var FocusFollowsIntoAPaneTakingOver = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The pane the focus follows into as it takes the section over gets its selection from the top of the diff it is given",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for i := range lines {
			lines[i] = strings.ToUpper(lines[i])
		}
		shell.UpdateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("M  file1").IsSelected(),
			)

		t.Views().Secondary().
			IsVisible().
			ScrollWheelDown().
			ScrollWheelDown().
			ScrollWheelDown().
			ScrollWheelDown().
			OriginY(8)

		t.Views().Files().Press(keys.Universal.FocusMainView)
		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("-line04"),
			)

		t.Shell().RunCommand([]string{"git", "reset"})
		t.GlobalPress(keys.Universal.Refresh)

		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Title(Equals("Unstaged changes")).
			OriginY(0).
			SelectedLines(
				Contains("-line01"),
			)
	},
})
View Source
var FocusFollowsStagedSide = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Unstaging from a fully staged file leaves the focus on the staged side, which keeps its pane",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED1\ntwo\nthree\nfour\nfive\nsix\nseven\nSTAGED2\neight\nnine\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("M  file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().IsInvisible()
		t.Views().Secondary().
			IsFocused().
			Title(Equals("Staged changes")).
			SelectedLines(
				Contains("+STAGED1"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("MM file1"),
		)
		t.Views().Main().
			IsVisible().
			Content(Contains("+STAGED1"))
		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+STAGED2"),
			)
	},
})
View Source
var FocusFollowsWhenPaneGoes = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Staging the last unstaged change takes the upper pane away, so the focus follows the lines into the lower one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nADDED\ntwo\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Title(Equals("Unstaged changes")).
			SelectedLines(
				Contains("+ADDED"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("M  file1"),
		)
		t.Views().Main().IsInvisible()
		t.Views().Secondary().
			IsFocused().
			Title(Equals("Staged changes")).
			SelectedLines(
				Contains("+ADDED"),
			)
	},
})
View Source
var FocusLeavesAnAlwaysSplitEmptyPane = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Configured to always split the diff, the emptied pane stays but the focus still leaves it",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
		cfg.GetUserConfig().Gui.SplitDiff = "always"
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\n")
		shell.UpdateFile("file1", "one\nSTAGED\ntwo\nthree\nUNSTAGED\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+STAGED"),
			)

		t.Shell().Commit("two")
		t.GlobalPress(keys.Universal.Refresh)

		t.Views().Secondary().
			IsVisible().
			Content(DoesNotContain("STAGED"))
		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+UNSTAGED"),
			)
	},
})
View Source
var FocusReturnsWhenSplitCollapses = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Unstaging the last staged change from the secondary pane brings the focus back to the main one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.UpdateFile("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\nUNSTAGED\neight\nnine\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("MM file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+STAGED"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains(" M file1"),
		)
		t.Views().Main().
			IsFocused().
			Content(Contains("+STAGED")).
			Content(Contains("+UNSTAGED")).
			SelectedLines(
				Contains("+STAGED"),
			)
	},
})
View Source
var HideSelectionWhenChangesVanish = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The main view's selection disappears along with the changes it was on",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Universal.Return)

		t.Views().Files().
			IsFocused().
			Press(keys.Universal.Remove).
			Tap(func() {
				t.ExpectPopup().Menu().
					Title(Equals("Discard changes")).
					Select(Contains("Discard all changes")).
					Confirm()
			}).
			IsEmpty()

		t.Views().Main().
			Content(Contains("No changed files")).
			SelectionIsHidden()
	},
})
View Source
var JumpToAFileOfTheDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Jump to a file of a commit's diff by picking it from a menu of the diff's files",
	ExtraCmdArgs: []string{},
	Skip:         false,

	Width:  100,
	Height: 20,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 600)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%03d", i+1)
		}
		shell.CreateFileAndAdd("aaa.txt", strings.Join(lines, "\n")+"\n")
		shell.CreateFileAndAdd("ccc.txt", "one\n")
		shell.CreateFileAndAdd("dir/bbb.txt", "one\n")

		shell.CreateFileAndAdd("zzz.txt", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("ccc.txt", "two\n")
		shell.Commit("two")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			SelectedLine(Contains("two")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Universal.JumpToFile)

		t.ExpectToast(Contains("There is only one file in this diff"))

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.Return)

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			SelectedLine(Contains("one")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Universal.JumpToFile)

		t.ExpectPopup().Menu().
			Title(Equals("Jump to file")).
			Lines(
				Equals("aaa.txt"),
				Equals("ccc.txt"),
				Equals("dir/bbb.txt"),
				Equals("zzz.txt"),
				Equals("Cancel"),
			).
			Select(Equals("dir/bbb.txt")).
			Confirm()

		t.Views().Main().
			IsFocused().
			TopVisibleLine(Contains("diff --git a/dir/bbb.txt b/dir/bbb.txt")).
			SelectedLines(
				Contains("diff --git a/dir/bbb.txt b/dir/bbb.txt"),
			).
			Press(keys.Universal.JumpToFile)

		t.ExpectPopup().Menu().
			Title(Equals("Jump to file")).
			Filter("ccc").
			Lines(
				Equals("ccc.txt"),
			).
			Confirm()

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("diff --git a/ccc.txt b/ccc.txt"),
			).
			Press(keys.Universal.Return)

		t.Views().Commits().
			IsFocused().
			SelectedLine(Contains("one")).
			Press(keys.Universal.JumpToFile)

		t.ExpectPopup().Menu().
			Title(Equals("Jump to file in diff")).
			Select(Equals("zzz.txt")).
			Confirm()

		t.Views().Commits().
			IsFocused().
			SelectedLine(Contains("one"))

		t.Views().Main().
			TopVisibleLine(Contains("diff --git a/zzz.txt b/zzz.txt"))

		t.Views().Branches().
			Focus().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().Content(DoesNotContain("Jump to file"))
			}).
			Cancel()

		t.Views().Commits().
			Focus().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().Content(Contains("Jump to file in diff"))
			}).
			Cancel()
	},
})
View Source
var JumpToAFileOnlyOverADiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The menu of the diff's files is offered only while the main view is showing a diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shared.CreateMergeConflictFiles(shell)
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			NavigateToLine(Contains("original")).
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().Content(Contains("Jump to file in diff"))
			}).
			Cancel()

		t.Views().Commits().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().
					Content(Contains("Jump to file")).
					Content(DoesNotContain("Jump to file in diff"))
			}).
			Cancel()

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.Return)

		t.Views().Files().
			Focus().
			NavigateToLine(Contains("UU file1")).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().Content(DoesNotContain("Jump to file"))
			}).
			Cancel()
	},
})
View Source
var KeepAWrappedLineCoveredAcrossARerender = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A selection over a line too long for the view still covers all of it after a re-render",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        80,
	Height:       20,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		long := strings.Repeat("word ", 40)
		lines := make([]string, 20)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		before := strings.Join(lines[:10], "\n") + "\n"
		after := strings.Join(lines[10:], "\n") + "\n"

		shell.CreateFileAndAdd("file1", before+long+"\n"+after)
		shell.Commit("one")

		shell.UpdateFile("file1", before+"CHANGED "+long+"\n"+after)
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-word word"),
				Contains("+CHANGED word"),
			).
			SelectedViewLineRange(8, 16).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			SelectedLines(
				Contains("-word word"),
				Contains("+CHANGED word"),
			).
			SelectedViewLineRange(9, 17)
	},
})
View Source
var KeepAnEmptiedPaneEmpty = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Selecting a file and moving back off it in rapid succession leaves the pane that the file filled empty",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file_a", "one\n")
		shell.CreateFileAndAdd("file_b", "one\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file_a", "STAGED\n")
		shell.UpdateFile("file_a", "UNSTAGED\n")
		shell.UpdateFile("file_b", "two\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			NavigateToLine(Contains("file_b"))

		t.Views().Secondary().
			IsInvisible()

		t.Views().Files().
			PressRapidly(keys.Universal.PrevItem, keys.Universal.NextItem).
			SelectedLine(Contains("file_b"))

		t.Views().Secondary().
			IsInvisible().
			Content(Equals(""))
	},
})

Both selection changes are handled before the next layout. Selecting file_a asks for its staged changes in the lower pane, whose task is only created after the layout. Selecting file_b again leaves that pane with nothing to show, and empties it right away. The pane is hidden then, but when it is shown again, it shows what it holds until its next render replaces it.

View Source
var KeepBothHalvesOfAChangeSelected = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A change selected on the one row a renderer draws it as is selected on both rows of a renderer that splits it",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true
		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{

			{Name: "unified", Command: `printf '\033]1717;1\007'; cat`},

			{Name: "columns", Command: `printf '\033]1717;1\007'; ` +
				`printf '\033]1717;1;f;;;file1\007file1\n'; ` +
				`printf '\033]1717;1;h;1;;file1\007@@\n'; ` +
				`printf '\033]1717;1;c;1;;file1\007one    one\n'; ` +
				`printf '\033]1717;1;d;2;2;file1\007two    \033]1717;1;a;2;;file1\007TWO\n'; ` +
				`printf '\033]1717;1;c;3;;file1\007three  three\n'; ` +
				`cat >/dev/null`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: columns (2 of 2)"))
			}).
			SelectedLines(
				Contains("two    TWO"),
			).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: unified (1 of 2)"))
			}).
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			)
	},
})
View Source
var KeepPositionByTheVisibleEndOfASelection = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A re-render keeps the place by the end of a selected hunk that is on screen when its other end isn't",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true

		cfg.GetUserConfig().Gui.ScrollHeight = 1
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 60)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{10, 11, 12, 13, 14, 15, 30, 45} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-line10"),
				Contains("-line11"),
				Contains("-line12"),
				Contains("-line13"),
				Contains("-line14"),
				Contains("-line15"),
				Contains("+LINE10"),
				Contains("+LINE11"),
				Contains("+LINE12"),
				Contains("+LINE13"),
				Contains("+LINE14"),
				Contains("+LINE15"),
			).
			SelectedLineIdx(8).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			OriginY(14).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			OriginY(15).
			SelectedLines(
				Contains("-line10"),
				Contains("-line11"),
				Contains("-line12"),
				Contains("-line13"),
				Contains("-line14"),
				Contains("-line15"),
				Contains("+LINE10"),
				Contains("+LINE11"),
				Contains("+LINE12"),
				Contains("+LINE13"),
				Contains("+LINE14"),
				Contains("+LINE15"),
			)
	},
})
View Source
var KeepPositionInBothPanesWhenChangingContextSize = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Changing the diff's context size keeps the place in the lower pane too, not only in the upper one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
		shell.GitAddAll()

		lines[39] = strings.ToUpper(lines[39])
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressTab()

		t.Views().Secondary().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(42).
			OriginY(21)
	},
})
View Source
var KeepPositionInBothPanesWhenIgnoringWhitespace = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Ignoring whitespace keeps the place in the lower pane too, not only in the upper one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 60)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		lines[4] = strings.ToUpper(lines[4])
		lines[14] = " " + lines[14]
		lines[24] = strings.ToUpper(lines[24])
		lines[44] = strings.ToUpper(lines[44])
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
		shell.GitAddAll()

		lines[59] = strings.ToUpper(lines[59])
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressTab()

		t.Views().Secondary().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line45"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			SelectedLines(
				Contains("-line45"),
			).
			SelectedLineIdx(26).
			OriginY(5)
	},
})
View Source
var KeepPositionInBothPanesWhenSwitchingDiffRenderers = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Switching to another diff renderer keeps the place in the lower pane too, not only in the upper one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "plain", Command: `printf '\033]1717;1\007'; cat`},

			{Name: "banner", Command: `printf '\033]1717;1\007'; printf 'rendered for you\n\n\n'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
		shell.GitAddAll()

		lines[39] = strings.ToUpper(lines[39])
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressTab()

		t.Views().Secondary().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: banner (2 of 2)"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(38).
			OriginY(17)
	},
})
View Source
var KeepPositionWhenChangingContextSize = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Changing the diff's context size keeps the line you were looking at where it was",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(42).
			OriginY(21).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 3"))
			}).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(28).
			OriginY(7).
			PressEscape()

		t.Views().Files().
			IsFocused().
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 3"))
			})

		t.Views().Main().
			SelectionIsHidden().
			OriginY(12)
	},
})
View Source
var KeepPositionWhenIgnoringWhitespace = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Ignoring whitespace keeps the line you were looking at where it was, even when it turns into a context line",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		lines[4] = strings.ToUpper(lines[4])
		lines[14] = " " + lines[14]
		lines[24] = strings.ToUpper(lines[24])
		lines[26] = lines[26] + " "
		lines[34] = " " + lines[34]
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line25"),
			).
			SelectedLineIdx(26).
			OriginY(14).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			SelectedLines(
				Contains("-line25"),
			).
			SelectedLineIdx(17).
			OriginY(5).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			SelectedLines(
				Contains("-line25"),
			).
			SelectedLineIdx(26).
			OriginY(14).
			Press(keys.Main.NextHunk).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("+line27"),
			).
			SelectedLineIdx(30).
			OriginY(14).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			SelectedLines(
				Contains(" line27"),
			).
			SelectedLineIdx(20).
			OriginY(4)
	},
})
View Source
var KeepPositionWhenIgnoringWhitespaceRemovesIt = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Ignoring whitespace where that takes the line you were on out of the diff lands on the nearest line it kept",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.CreateFileAndAdd("file2", "one\ntwo\nthree\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		lines[34] = " " + lines[34]
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")

		shell.UpdateFile("file2", "  one\n  two\n  three\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			SelectNextItem().
			SelectedLine(Contains("file1")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			SelectedLines(
				Contains(" line28"),
			).
			SelectedLineIdx(30).
			OriginY(14).
			Press(keys.Universal.ToggleWhitespaceInDiffView).
			PressEscape()

		t.Views().Files().
			IsFocused().
			SelectNextItem().
			SelectedLine(Contains("file2")).
			Press(keys.Universal.ToggleWhitespaceInDiffView)

		t.Views().Main().
			Content(Equals(""))
	},
})
View Source
var KeepPositionWhenSwitchingDiffRenderers = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Switching to another diff renderer keeps the line you were looking at where it was",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "plain", Command: `printf '\033]1717;1\007'; cat`},

			{Name: "banner", Command: `printf '\033]1717;1\007rendered for you\n\n\n'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: banner (2 of 2)"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(38).
			OriginY(17).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: plain (1 of 2)"))
			}).
			SelectedLines(
				Contains("-line35"),
			).
			SelectedLineIdx(35).
			OriginY(14)
	},
})
View Source
var KeepPositionWhenTheSelectionIsOffScreen = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A re-render keeps the lines that are on screen where they are, not a selection scrolled away from",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Gui.ScrollHeight = 15
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 60)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35, 45, 55} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-line05"),
			).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			OriginY(30).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			OriginY(21).
			SelectedLines(
				Contains("-line05"),
			).
			SelectedLineIdx(7)
	},
})
View Source
var KeepScrollWhenTheDiffCantBeRead = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Changing the context size under a diff renderer whose rows can't be placed keeps the scroll position rather than jumping to the top",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "opaque", Command: `sed -e 's/^/| /'`},
		}
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain)

		t.Views().Main().
			Content(Contains("| +LINE05")).
			OriginY(6).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.IncreaseContextInDiffView)
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			OriginY(6)
	},
})
View Source
var KeepSelectedRangeWhenChangingContextSize = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A range selection still covers the same lines of the diff after the context size changes",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.NextHunk).
			Press(keys.Main.NextHunk).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			Press(keys.Universal.NextItem).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-line25"),
				Contains("+LINE25"),
				Contains(" line26"),
				Contains(" line27"),
			).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 4"))
			}).
			SelectedLines(
				Contains("-line25"),
				Contains("+LINE25"),
				Contains(" line26"),
				Contains(" line27"),
			).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 3"))
			}).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 1"))
			}).
			SelectedLines(
				Contains("-line25"),
				Contains("+LINE25"),
				Contains(" line26"),
			).
			PressEscape().
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			Press(keys.Universal.IncreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 3"))
			}).
			SelectedLines(
				Contains(" line26"),
			).
			Press(keys.Universal.NextItem).
			Press(keys.Universal.RangeSelectUp).
			Press(keys.Universal.RangeSelectUp).
			Press(keys.Universal.RangeSelectUp).
			SelectedLines(
				Contains("-line25"),
				Contains("+LINE25"),
				Contains(" line26"),
				Contains(" line27"),
			).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 2"))
			}).
			Press(keys.Universal.DecreaseContextInDiffView).
			Tap(func() {
				t.ExpectToast(Equals("Changed diff context size to 1"))
			}).
			SelectedLines(
				Contains("-line25"),
			)
	},
})
View Source
var KeepSelectionAfterMovingPatchOut = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Moving a custom patch out of a commit leaves the focused main view's selection on a change that is still there",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "ONE\ntwo\nTHREE\nfour\nFIVE\n")
		shell.Commit("commit to move a patch out of")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move a patch out of").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-one"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-one"),
				Contains("+ONE"),
			).
			PressPrimaryAction()

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("-one")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+THREE")).
			SelectedLines(
				Contains("-one"),
				Contains("+ONE"),
				Contains(" two"),
				Contains("-three"),
				Contains("+THREE"),
			)

		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.Views().Main().
			IsFocused().
			Content(DoesNotContain("+ONE")).
			SelectedLines(
				Contains("-three"),
			)
	},
})
View Source
var KeepSelectionVisibleWhenDiffShrinks = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The selection stays on the content when a re-render leaves the diff with fewer lines than the selection was on",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "plain", Command: `printf '\033]1717;1\007'; cat`},

			{Name: "shrinking", Command: `printf '\033]1717;1\007'; ` +
				`sed -e 's/@@ -1,5 +1,5 @@/@@ -1,5 +1,4 @@/' -e '$d'`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nFIVE\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.GotoBottom).
			SelectedLines(
				Contains("+FIVE"),
			).
			Press(keys.Universal.CycleDiffRenderers).
			Tap(func() {
				t.ExpectToast(Equals("Diff renderer: shrinking (2 of 2)"))
			})

		t.Views().Main().
			SelectionIsActive().
			SelectedLineIdx(10).
			SelectedLines(
				Contains("-five"),
			)
	},
})
View Source
var MoveMultiFileRangeToIndex = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a multi-file range from a commit to the index",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "first line\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "first line\nsecond line\n")
		shell.CreateFileAndAdd("file2", "file two content\n")
		shell.CreateFileAndAdd("file3", "file three content\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  M file1"),
				Equals("  A file2"),
				Equals("  A file3"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+second line")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+file two content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().
			Content(Contains("second line")).
			Content(Contains("file two content"))

		t.Common().SelectPatchOption(MatchesRegexp(`Move patch out into index$`))

		t.Views().Files().
			Focus().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  M  file1"),
				Equals("  A  file2"),
			)
		t.Views().Secondary().Content(Contains("second line"))
		t.Views().Files().NavigateToLine(Contains("file2"))
		t.Views().Secondary().Content(Contains("file two content"))
	},
})
View Source
var MoveOnWhenThePatchMarksRewrapTheDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Taking the first line into a custom patch moves the selection on to the next change, although the marks that come with the patch narrow the diff and wrap a line above the selection",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file", "one\nTWO\nthree\nFOUR\nfive\n")

		shell.CreateFileAndAdd("many", strings.Repeat("line\n", 300))
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+TWO")).
			PressPrimaryAction().
			MarkedLines(
				Contains("+TWO"),
			).
			SelectedLines(
				Contains("-four"),
			)
	},
})
View Source
var MovePartOfAdjacentAddedLinesToIndex = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move only one of two adjacent added lines from a commit to the index",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "1st line\n2nd line\n")
		shell.Commit("commit to move from")

		shell.UpdateFileAndAdd("unrelated-file", "")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+1st line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.Views().Main().
			IsFocused().
			Content(Contains("+2nd line").DoesNotContain("1st line"))
		t.Views().Files().
			Focus().
			ContainsLines(
				Contains("M").Contains("file1"),
			)
		t.Views().Secondary().Content(Contains("+1st line\n 2nd line"))
	},
})
View Source
var MovePartialPatchToIndex = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move part of a file's changes from a commit to the index",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "first line\nsecond line\nthird line\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "first line2\nsecond line\nthird line2\n")
		shell.Commit("second commit")

		shell.CreateFileAndAdd("file2", "file1 content")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("second commit"),
				Contains("first commit"),
			).
			NavigateToLine(Contains("second commit")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains(`-first line`)).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains(`-first line`),
				Contains(`+first line2`),
			).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().ContainsLines(
			Contains(`-first line`),
			Contains(`+first line2`),
			Contains(` second line`),
			Contains(` third line`),
		)

		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.Views().Files().Lines(
			Contains("M").Contains("file1"),
		)
		t.Views().Main().
			IsFocused().
			ContainsLines(
				Contains(` first line`),
				Contains(` second line`),
				Contains(`-third line`),
				Contains(`+third line2`),
			)

		t.Views().Files().Focus()
		t.Views().Secondary().ContainsLines(
			Contains(`-first line`),
			Contains(`+first line2`),
			Contains(` second line`),
			Contains(` third line2`),
		)
	},
})
View Source
var MovePartialPatchToLaterCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move one of two adjacent additions from a commit to a later commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "1st line\n2nd line\n")
		shell.Commit("commit to move from")

		shell.UpdateFileAndAdd("unrelated-file", "")
		shell.Commit("destination commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("destination commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+1st line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Commits().Focus().SelectPreviousItem()
		t.Common().SelectPatchOption(Contains("Move patch to selected commit"))

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("destination commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Contains("file1"),
				Contains("unrelated-file"),
			).
			SelectNextItem().
			Tap(func() {
				t.Views().Main().Content(Contains("+1st line\n 2nd line"))
			}).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().Content(Contains("+2nd line").DoesNotContain("1st line"))
			})
	},
})
View Source
var MovePartialPatchToNewCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move one of two adjacent additions from a commit to a new commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "1st line\n2nd line\n")
		shell.Commit("commit to move from")

		shell.UpdateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+1st line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit after the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("third commit"),
				Contains("new commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().Content(Contains("+1st line\n 2nd line"))
			}).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().Content(Contains("+2nd line").DoesNotContain("1st line"))
			})
	},
})
View Source
var MovePatchFromAddedFileToEarlierCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move part of an added file from a commit to an earlier commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("first commit")
		shell.EmptyCommit("destination commit")
		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("commit to move from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move from").IsSelected(),
				Contains("destination commit"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+2nd line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Commits().Focus().SelectNextItem()
		t.Common().SelectPatchOption(Contains("Move patch to selected commit"))

		t.Common().AcknowledgeConflicts()

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("AA").Contains("file"),
			).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			TopLines(
				Contains("<<<<<<< HEAD"),
				Contains("2nd line"),
				Contains("======="),
				Contains("1st line"),
				Contains("2nd line"),
				Contains("3rd line"),
				Contains(">>>>>>>"),
			).
			SelectNextItem().
			PressPrimaryAction()

		t.Common().ContinueOnConflictsResolved("rebase")

		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move from").IsSelected(),
				Contains("destination commit"),
				Contains("first commit"),
			).
			NavigateToLine(Contains("destination commit")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals("+2nd line"),
				)
			}).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			NavigateToLine(Contains("commit to move from")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("M file").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals("+1st line"),
					Equals(" 2nd line"),
					Equals("+3rd line"),
				)
			})
	},
})
View Source
var MovePatchFromAddedFileToIndexWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move part of an added file from a commit to the index, causing a conflict",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("first commit")

		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("commit to move from")
		shell.UpdateFileAndAdd("file1", "1st line\n2nd line changed\n3rd line\n")
		shell.Commit("conflicting change")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("conflicting change").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+2nd line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch out into index"))
		t.Common().AcknowledgeConflicts()

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("UU").Contains("file1"),
			).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			ContainsLines(
				Contains("1st line"),
				Contains("<<<<<<< HEAD"),
				Contains("======="),
				Contains("2nd line changed"),
				Contains(">>>>>>>"),
				Contains("3rd line"),
			).
			SelectNextItem().
			PressPrimaryAction()

		t.Common().ContinueOnConflictsResolved("rebase")

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("Applied patch to 'file1' with conflicts")).
			Confirm()

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("UU").Contains("file1"),
			).
			PressEnter()

		t.Views().MergeConflicts().
			TopLines(
				Contains("1st line"),
				Contains("<<<<<<< ours"),
				Contains("2nd line changed"),
				Contains("======="),
				Contains("2nd line"),
				Contains(">>>>>>> theirs"),
				Contains("3rd line"),
			).
			IsFocused()
	},
})
View Source
var MovePatchFromAddedFileToNewCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move part of an added file from a commit to a new commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("first commit")

		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("commit to move from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move from").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+2nd line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit after the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("new commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("M file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals(" 1st line"),
					Equals("+2nd line"),
					Equals(" 3rd line"),
				)
			}).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			NavigateToLine(Contains("commit to move from")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals("+1st line"),
					Equals("+3rd line"),
				)
			})
	},
})
View Source
var MovePatchFromDeletedFileToNewCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move part of a deleted file from a commit to a new commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("first commit")
		shell.DeleteFileAndAdd("file1")
		shell.Commit("commit to move from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move from").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("D file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("-2nd line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit after the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("new commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("D file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals("-2nd line"),
				)
			}).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			NavigateToLine(Contains("commit to move from")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("M file1").IsSelected(),
			).
			Tap(func() {
				t.Views().Main().ContainsLines(
					Equals("-1st line"),
					Equals(" 2nd line"),
					Equals("-3rd line"),
				)
			})
	},
})
View Source
var MovePatchToEarlierCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to an earlier commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateDir("dir")
		shell.CreateFileAndAdd("dir/file1", "file1 content")
		shell.CreateFileAndAdd("dir/file2", "file2 content")
		shell.Commit("first commit")

		shell.CreateFileAndAdd("unrelated-file", "")
		shell.Commit("destination commit")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with old changes")
		shell.DeleteFileAndAdd("dir/file2")
		shell.CreateFileAndAdd("dir/file3", "file3 content")
		shell.Commit("commit to move from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to move from").IsSelected(),
				Contains("destination commit"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+file3 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Commits().Focus().SelectNextItem()
		t.Common().SelectPatchOption(Contains("Move patch to selected commit"))

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("commit to move from"),
				Contains("destination commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  ▼ dir"),
				Equals("    M file1"),
				Equals("    D file2"),
				Equals("    A file3"),
				Equals("  A unrelated-file"),
			).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectPreviousItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("(none)"),
			)
	},
})
View Source
var MovePatchToIndex = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to the index",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content\n")
		shell.CreateFileAndAdd("file2", "file2 content\n")
		shell.Commit("first commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("first commit").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Contains("file1"),
				Contains("file2"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("+file1 content"))

		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.Views().Files().Lines(
			Contains("A").Contains("file1"),
		)
		t.Views().Main().
			IsFocused().
			Content(Contains("+file2 content"))
		t.Views().Commits().Lines(
			Contains("first commit").IsSelected(),
		)

		t.Views().Files().Focus()
		t.Views().Secondary().Content(Contains("file1 content"))
	},
})
View Source
var MovePatchToIndexWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to the index, causing a conflict",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "file1 content with old changes")
		shell.Commit("second commit")

		shell.UpdateFileAndAdd("file1", "file1 content with new changes")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("second commit"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch out into index"))
		t.Common().AcknowledgeConflicts()

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("UU").Contains("file1"),
			).
			PressEnter()

		t.Views().MergeConflicts().
			IsFocused().
			ContainsLines(
				Contains("<<<<<<< HEAD").IsSelected(),
				Contains("file1 content").IsSelected(),
				Contains("=======").IsSelected(),
				Contains("file1 content with new changes"),
				Contains(">>>>>>>"),
			).
			PressPrimaryAction()

		t.Common().ContinueOnConflictsResolved("rebase")

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("Applied patch to 'file1' with conflicts")).
			Confirm()

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("UU").Contains("file1"),
			).
			PressEnter()

		t.Views().MergeConflicts().
			TopLines(
				Contains("<<<<<<< ours"),
				Contains("file1 content"),
				Contains("======="),
				Contains("file1 content with old changes"),
				Contains(">>>>>>> theirs"),
			).
			IsFocused()
	},
})
View Source
var MovePatchToIndexWithCustomDiffConfig = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Moving a patch to the index works even if diff.noprefix or diff.external are set",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content\n")
		shell.Commit("first commit")

		shell.SetConfig("diff.noprefix", "true")
		shell.SetConfig("diff.external", "echo")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("first commit").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Secondary().Content(Contains("+file1 content"))
		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.Views().CommitFiles().Lines(Equals("(none)"))
		t.Views().Files().Lines(
			Contains("A").Contains("file1"),
		)
	},
})
View Source
var MovePatchToIndexWithModifiedFile = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to the index with a conflicting working-tree change",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n")
		shell.Commit("first commit")
		shell.UpdateFileAndAdd("file1", "11\n2\n3\n4\n")
		shell.Commit("second commit")
		shell.UpdateFile("file1", "111\n2\n3\n4\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("M file1"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-1")).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("-1\n+11"))

		t.Common().SelectPatchOption(Contains("Move patch out into index"))

		t.ExpectPopup().Confirmation().Title(Equals("Must stash")).
			Content(Contains("Pulling a patch out into the index requires stashing and unstashing your changes.")).
			Confirm()

		t.Views().Files().
			Focus().
			Lines(
				Equals("MM file1"),
			)

		t.Views().Main().Content(Contains("-11\n+111\n"))
		t.Views().Secondary().Content(Contains("-1\n+11\n"))
		t.Views().Stash().IsEmpty()
	},
})
View Source
var MovePatchToLaterCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to a later commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateDir("dir")
		shell.CreateFileAndAdd("dir/file1", "file1 content")
		shell.CreateFileAndAdd("dir/file2", "file2 content")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with old changes")
		shell.DeleteFileAndAdd("dir/file2")
		shell.CreateFileAndAdd("dir/file3", "file3 content")
		shell.Commit("commit to move from")

		shell.CreateFileAndAdd("unrelated-file", "")
		shell.Commit("destination commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("destination commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+file3 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Commits().Focus().SelectPreviousItem()
		t.Common().SelectPatchOption(Contains("Move patch to selected commit"))

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("destination commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  ▼ dir"),
				Equals("    M file1"),
				Equals("    D file2"),
				Equals("    A file3"),
				Equals("  A unrelated-file"),
			).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("(none)"),
			)
	},
})
View Source
var MovePatchToNewCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to a new commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateDir("dir")
		shell.CreateFileAndAdd("dir/file1", "file1 content")
		shell.CreateFileAndAdd("dir/file2", "file2 content")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with old changes")
		shell.DeleteFileAndAdd("dir/file2")
		shell.CreateFileAndAdd("dir/file3", "file3 content")
		shell.Commit("commit to move from")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with new changes")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+file3 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit after the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("third commit"),
				Contains("new commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("(none)"),
			)
	},
})
View Source
var MovePatchToNewCommitBefore = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch from a commit to a new commit before the source",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateDir("dir")
		shell.CreateFileAndAdd("dir/file1", "file1 content")
		shell.CreateFileAndAdd("dir/file2", "file2 content")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with old changes")
		shell.DeleteFileAndAdd("dir/file2")
		shell.CreateFileAndAdd("dir/file3", "file3 content")
		shell.Commit("commit to move from")

		shell.UpdateFileAndAdd("dir/file1", "file1 content with new changes")
		shell.Commit("third commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("third commit").IsSelected(),
				Contains("commit to move from"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("-file1 content")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+file3 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit before the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("third commit"),
				Contains("commit to move from").IsSelected(),
				Contains("new commit"),
				Contains("first commit"),
			).
			SelectNextItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("dir").IsSelected(),
				Contains("  M file1"),
				Contains("  D file2"),
				Contains("  A file3"),
			).
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectPreviousItem().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("(none)"),
			)
	},
})
View Source
var MovePatchToNewCommitInStackedBranch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Move a patch to a new commit after the last commit of a branch in the middle of a stack",
	ExtraCmdArgs: []string{},
	Skip:         false,
	GitVersion:   AtLeast("2.38.0"),
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Git.Log.ShowGraph = "never"
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.
			EmptyCommit("commit-01").
			NewBranch("branch1").
			EmptyCommit("commit-02").
			CreateFileAndAdd("file1", "file1 content").
			CreateFileAndAdd("file2", "file2 content").
			Commit("commit-03").
			NewBranch("branch2").
			CreateNCommitsStartingAt(2, 4)

		shell.SetConfig("rebase.updateRefs", "true")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("CI commit-05").IsSelected(),
				Contains("CI commit-04"),
				Contains("CI * commit-03"),
				Contains("CI commit-02"),
				Contains("CI commit-01"),
			).
			NavigateToLine(Contains("commit-03")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Equals("  A file1"),
				Equals("  A file2"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Move patch into new commit after the original commit"))

		t.ExpectPopup().CommitMessagePanel().
			InitialText(Equals("")).
			Type("new commit").Confirm()

		t.Views().Commits().
			IsFocused().
			Lines(
				Contains("CI commit-05"),
				Contains("CI commit-04"),
				Contains("CI * new commit").IsSelected(),
				Contains("CI commit-03"),
				Contains("CI commit-02"),
				Contains("CI commit-01"),
			)
	},
})
View Source
var NavigateByHunkAndFile = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Jump from hunk to hunk and from file to file in the focused main view of a commit's diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.CreateFileAndAdd("file2", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\ntwo\nTHREE\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
		shell.UpdateFileAndAdd("file2", "one\ntwo\nTHREE\n")
		shell.Commit("two")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("two").IsSelected(),
				Contains("one"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-nine"),
			).
			Press(keys.Main.PrevHunk).
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.NextFile).
			SelectedLines(
				Contains("diff --git a/file2 b/file2"),
			).
			Press(keys.Main.NextFile).
			SelectedLines(
				Contains("diff --git a/file2 b/file2"),
			).
			Press(keys.Main.PrevFile).
			SelectedLines(
				Contains("diff --git a/file1 b/file1"),
			).
			Press(keys.Main.NextHunk).
			Press(keys.Universal.RangeSelectDown).
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
			).
			Press(keys.Main.NextHunk).
			SelectedLines(
				Contains("-nine"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Main.PrevHunk).
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
				Contains(" four"),
				Contains(" five"),
				Contains(" six"),
				Contains(" seven"),
				Contains(" eight"),
				Contains("-nine"),
			)
	},
})
View Source
var NoDiffStatLinksUnderAnExternalDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The files named in the diffstat are not linked under a diff renderer that says nothing about its rows",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        100,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "opaque", Type: "extDiff", Command: `sh -c 'echo EXT'`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("aaa.txt", "one\n")
		shell.CreateFileAndAdd("zzz.txt", "one\n")
		shell.Commit("one")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			SelectedLine(Contains("one"))

		t.Views().Main().
			TopLines(
				Contains("commit"),
				Contains("Author:"),
				Contains("Date:"),
				Equals(""),
				Contains("one"),
				Equals("---"),
				Contains("aaa.txt"),
				Contains("zzz.txt"),
				Contains("2 files changed"),
			).
			Click(2, 7)

		t.Views().Main().IsFocused()
	},
})
View Source
var NoSelectionOverABinaryDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A diff with nothing selectable in it shows no selection, however it came to be showing",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("text", "one\ntwo\nthree\n")
		shell.CreateFileAndAdd("binary", "\x00one\x00two\x00")
		shell.Commit("one")

		shell.UpdateFile("text", "one\nTWO\nthree\n")
		shell.UpdateFile("binary", "\x00one\x00TWO\x00")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			NavigateToLine(Contains("binary")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden().
			Tap(func() {
				t.GlobalPress(keys.Universal.Refresh)
			}).
			SelectionIsHidden()

		t.Views().Files().
			Focus().
			NavigateToLine(Contains("▼ /")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Main.ToggleSelectHunk).
			PressPrimaryAction().
			SelectionIsHidden()
	},
})
View Source
var NoSelectionOverACommitLog = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view over a branch's commit log shows no selection, even for a log too long to be read in one go",
	ExtraCmdArgs: []string{},
	Skip:         false,

	Width:       100,
	Height:      20,
	SetupConfig: func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateNCommits(60)
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("add file1")
		shell.UpdateFile("file1", "one\ntwo modified\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			PressEscape()

		t.Views().Branches().
			Focus()

		t.Views().Main().
			Content(Contains("commit-60"))

		t.Views().Branches().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden()
	},
})
View Source
var NoSelectionOverAConflictHint = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The hint for a conflict that has to be resolved by picking a side shows no selection, diff and all",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.ShowFileTree = false
		config.GetUserConfig().OS.EditAtLine = "echo {{filename}}:{{line}} > edit-command"
	},
	SetupRepo: func(shell *Shell) {
		shell.RunShellCommand(`echo 1 > foo && echo 1 > bar`)
		shell.RunShellCommand(`git checkout -b base && git add . && git commit -m base`)

		shell.RunShellCommand(`git checkout -b theirs`)
		shell.RunShellCommand(`git rm foo && echo 2 > bar && git add bar && git commit -m theirs`)

		shell.RunShellCommand(`git checkout base && git checkout -b ours`)
		shell.RunShellCommand(`echo 2 > foo && git add foo && git rm bar && git commit -m ours`)

		shell.RunCommandExpectError([]string{"git", "merge", "theirs"})
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			NavigateToLine(Contains("DU bar")).
			Tap(func() {
				t.Views().Main().
					Content(Contains("Conflict: this file was deleted in the current changes")).
					Content(Contains("Incoming changes:")).
					Content(Contains("+2"))
			}).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden().
			PressPrimaryAction().
			Tap(func() {
				t.ExpectToast(Contains("There is nothing to select here"))
			}).
			Click(0, 17).
			SelectedLine(Contains("+2")).
			AltClick(0, 17).
			Tap(func() {
				t.FileSystem().FileContent("edit-command", Contains("/repo/bar:1\n"))
			})
	},
})
View Source
var NoSelectionWhenNoChanges = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view when there are no changes shows no selection, and navigating doesn't conjure one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("one")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			IsEmpty().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("No changed files")).
			SelectionIsHidden().
			Press(keys.Universal.GotoTop).
			SelectionIsHidden()
	},
})
View Source
var OpenPullRequestOnlyOverACommitsDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Opening a diff line in the pull request is offered over a commit's own diff, and refused over the other diffs the main view shows",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")

		shell.UpdateFile("file1", "one\nTWO\nTHREE\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			Focus().
			SelectedLine(Contains("file1")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {

				t.Views().Menu().
					Content(Contains("Go to next file")).
					Content(DoesNotContain("Open pull request at selected line"))
			}).
			Cancel()

		t.Views().Commits().
			Focus().
			SelectedLine(Contains("second commit")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Commits.OpenPullRequestInBrowser)

		t.ExpectPopup().Alert().
			Title(Equals("Error")).
			Content(Contains("No pull request found for this branch")).
			Confirm()

		t.Views().Main().
			IsFocused().
			PressPrimaryAction().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			Press(keys.Commits.OpenPullRequestInBrowser)

		t.ExpectToast(Contains("Not available for the custom patch"))

		t.Views().Commits().
			Focus().
			Press(keys.Universal.DiffingMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Diffing")).
			Select(MatchesRegexp(`Diff \w+`)).
			Confirm()

		t.Views().Commits().
			SelectNextItem().
			SelectedLine(Contains("first commit")).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			Press(keys.Commits.OpenPullRequestInBrowser)

		t.ExpectToast(Contains("Not available in diffing mode"))
	},
})
View Source
var PatchMarksFollowARendererSwitch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Switching diff renderers mid-build leaves the marks on the lines that are in the custom patch, wherever the new rendering puts them",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "one", Command: `printf '\033]1717;1\007RENDERED BY ONE\n'; cat`},
			{Name: "two", Command: `printf '\033]1717;1\007RENDERED BY TWO\nAND ONE MORE LINE\n'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("RENDERED BY ONE")).
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction().
			MarkedLines(
				Contains("-two"),
			).
			Press(keys.Universal.CycleDiffRenderers)

		t.ExpectToast(Equals("Diff renderer: two (2 of 2)"))

		t.Views().Main().
			Content(Contains("AND ONE MORE LINE")).
			MarkedLines(
				Contains("-two"),
			)
	},
})
View Source
var PatchMarksShowWheneverTheirDiffIsOnScreen = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The marks over the lines in the custom patch are shown whenever the main view shows the diff the patch is built from, whether or not it has the focus, and not over the diff of another commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction().
			MarkedLines(
				Contains("-two"),
			).
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().IsFocused()
		t.Views().Main().MarkedLines(
			Contains("-two"),
		)

		t.Views().Secondary().Press(keys.Universal.Return)

		t.Views().Commits().IsFocused()
		t.Views().Main().MarkedLines(
			Contains("-two"),
		)

		t.Views().Commits().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			SelectNextItem()

		t.Views().Main().NoMarkedLines()

		t.Views().Commits().SelectPreviousItem()

		t.Views().Main().MarkedLines(
			Contains("-two"),
		)
	},
})
View Source
var RangeSelectDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Select a range of diff lines in the focused main view, both sticky and with shift",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nFOUR\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-three"),
				Contains("-four"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			SelectedLines(
				Contains("-four"),
			).
			Press(keys.Universal.RangeSelectDown).
			SelectedLines(
				Contains("-four"),
				Contains("+THREE"),
			).
			Press(keys.Universal.RangeSelectUp).
			SelectedLines(
				Contains("-four"),
			).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("+THREE"),
			)
	},
})
View Source
var RawFallbackUnderAnExternalDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view under an external diff that says nothing about its rows brings git's own diff, keeping the scroll position",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Name: "opaque", Type: "extDiff", Command: `sh -c 'seq -f "EXT-%g" 40'`},
		}
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 40)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{5, 15, 25, 35} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Main().
			Content(Contains("EXT-1")).
			Tap(func() {
				t.Views().Files().
					IsFocused().
					Press(keys.Universal.ScrollDownMain).
					Press(keys.Universal.ScrollDownMain).
					Press(keys.Universal.ScrollDownMain)
			}).
			OriginY(6).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.FocusMainView)
			}).
			IsFocused().
			Content(Contains("+LINE05")).
			Content(DoesNotContain("EXT-1")).
			OriginY(6).
			SelectionIsActive()
	},
})
View Source
var RemoveContentChangeFromRenamedFile = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Remove a renamed file's content change from a commit while keeping its rename",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("original", "line1\nline2\nline3\nline4\nline5\n")
		shell.Commit("first commit")

		shell.RenameFileInGit("original", "renamed")
		shell.UpdateFileAndAdd("renamed", "line1\nline2 changed\nline3\nline4\nline5\n")
		shell.Commit("rename with modification")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("rename with modification").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("original → renamed").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("rename from original").Contains("rename to renamed")).
			SelectedLines(Contains("-line2")).
			Press(keys.Universal.ToggleRangeSelect).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-line2"),
				Contains("+line2 changed"),
			).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))

		t.Views().Secondary().
			ContainsLines(
				Contains("diff --git a/renamed b/renamed"),
				Contains("index"),
				Contains("--- a/renamed"),
				Contains("+++ b/renamed"),
			).
			ContainsLines(
				Contains(" line1"),
				Contains("-line2"),
				Contains("+line2 changed"),
				Contains(" line3"),
			)

		t.Common().SelectPatchOption(Contains("Remove patch from original commit"))

		t.Views().CommitFiles().Lines(
			Contains("original → renamed").IsSelected(),
		)
		t.Views().Main().
			IsFocused().
			Content(DoesNotContain("line2 changed"))
		t.Views().Commits().Lines(
			Contains("rename with modification").IsSelected(),
			Contains("first commit"),
		)
	},
})
View Source
var RemoveLinesFromTheCustomPatch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Take a line back out of the custom patch from the pane previewing it, where the patch's own numbering is not the commit's",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nadded a\ntwo\nadded b\nthree\nadded c\nfour\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+added a"),
			).
			NavigateToLine(Contains("+added b")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+added c")).
			PressPrimaryAction().
			MarkedLines(
				Contains("+added b"),
				Contains("+added c"),
			)

		t.Views().Secondary().ContainsLines(
			Contains("+added b"),
			Contains(" three"),
			Contains("+added c"),
		)

		t.Views().Main().Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+added b"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("+added c"),
			).
			Content(DoesNotContain("+added b"))

		t.Views().Main().MarkedLines(
			Contains("+added c"),
		)

		t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

		t.Views().Files().
			Focus().
			Lines(
				Contains("M").Contains("file1"),
			)

		t.Views().Secondary().
			ContainsLines(
				Contains("-added c"),
			).
			Content(DoesNotContain("+added b"))
	},
})
View Source
var RemovePartOfAddedFileFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Remove a custom patch containing one line of an added file from its commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("first commit")
		shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
		shell.Commit("commit to remove from")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("commit to remove from").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("A file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("+2nd line")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Common().SelectPatchOption(Contains("Remove patch from original commit"))

		t.Views().Main().
			IsFocused().
			ContainsLines(
				Equals("+1st line"),
				Equals("+3rd line"),
			)
	},
})
View Source
var RemovePatchFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Remove a whole-file custom patch from its original commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content\n")
		shell.CreateFileAndAdd("file2", "file2 content\n")
		shell.Commit("first commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("first commit").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Equals("▼ /").IsSelected(),
				Contains("file1"),
				Contains("file2"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("+file1 content"))
		t.Common().SelectPatchOption(Contains("Remove patch from original commit"))

		t.Views().Files().IsEmpty()
		t.Views().Main().
			IsFocused().
			Content(Contains("+file2 content"))
		t.Views().Commits().Lines(
			Contains("first commit").IsSelected(),
		)
	},
})
View Source
var RenderTheDiffBesideThePatchMarks = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A diff that the custom patch's marks are shown over is rendered to the width they leave it, so that a line as wide as the view still fits beside them, whether or not the view has the focus",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file", "one\nTWO\nthree\n")

		shell.CreateFileAndAdd("many", strings.Repeat("line\n", 300))
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressPrimaryAction().
			MarkedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			ContainsViewLines(
				Contains("many | 300"),
				Contains("2 files changed"),
			)

		t.Views().Main().Press(keys.Universal.Return)

		t.Views().Commits().IsFocused()
		t.Views().Main().
			MarkedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			ContainsViewLines(
				Contains("many | 300"),
				Contains("2 files changed"),
			)
	},
})
View Source
var ResetAPatchBuiltFromACommitsDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Reset a custom patch built from a commit's diff without ever entering the commit's files, and stay in the diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
			).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().IsVisible().Content(Contains("-two"))

		t.Common().SelectPatchOption(Contains("Reset patch"))

		t.Views().Information().Content(DoesNotContain("Building patch"))
		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Content(Contains("-two"))
	},
})
View Source
var ResetPatchWithEscape = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Reset a custom patch after escaping from the focused commit diff",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content")
		shell.Commit("first commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("first commit").IsSelected(),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))

		t.Views().Main().PressEscape()
		t.Views().CommitFiles().IsFocused().PressEscape()
		t.Views().Commits().IsFocused().PressEscape()

		t.Views().Information().Content(DoesNotContain("Building patch"))
	},
})
View Source
var ResetThePatchFromThePaneShowingIt = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Reset a custom patch while the focus is in the pane previewing it",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			).
			PressPrimaryAction().
			Press(keys.Universal.TogglePanel)

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().
			IsFocused().
			Content(Contains("-two"))

		t.Common().SelectPatchOption(Contains("Reset patch"))

		t.Views().Information().Content(DoesNotContain("Building patch"))
		t.Views().Secondary().IsInvisible()
		t.Views().Main().
			IsFocused().
			Content(Contains("-two"))
	},
})
View Source
var SearchCollapsesTheSelection = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Searching the focused main view leaves a single line selected at the match, whatever was selected before",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
			).
			FilterOrSearch("NINE").
			SelectedLines(
				Contains("+NINE"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			Press(keys.Universal.NextMatch).
			SelectedLines(
				Contains("+NINE"),
			)
	},
})
View Source
var SearchFollowsTheSelection = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stepping to the next match in the focused main view carries on from the selection",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "")
		shell.Commit("one")

		shell.UpdateFile("file1", "NEEDLE a\ntwo\nNEEDLE b\nfour\nNEEDLE c\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			FilterOrSearch("NEEDLE").
			SelectedLines(Contains("+NEEDLE a")).
			Tap(func() {
				t.Views().Search().Content(Contains("matches for 'NEEDLE' (1 of 3)"))
			}).
			SelectNextItem().
			SelectNextItem().
			SelectNextItem().
			SelectedLines(Contains("+four")).
			Tap(func() {
				t.Views().Search().Content(Contains("matches for 'NEEDLE' (2 of 3)"))
			}).
			Press(keys.Universal.NextMatch).
			SelectedLines(Contains("+NEEDLE c"))
	},
})
View Source
var SelectBelowALongCommitMessage = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view over a commit whose diff begins below a very long commit message still shows a selection",
	ExtraCmdArgs: []string{},
	Skip:         false,

	Width:       100,
	Height:      20,
	SetupConfig: func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("first commit")

		body := make([]string, 1000)
		for i := range body {
			body[i] = fmt.Sprintf("message line %d", i+1)
		}
		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("a commit with a great deal to say\n\n" + strings.Join(body, "\n"))

		shell.EmptyCommit("nothing to see here")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			Lines(
				Contains("nothing to see here").IsSelected(),
				Contains("a commit with a great deal to say"),
				Contains("first commit"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden().
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("-two")).
			SelectionIsActive()
	},
})
View Source
var SelectBelowALongDiffstat = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view over a commit whose diff begins below a long diffstat still shows a selection",
	ExtraCmdArgs: []string{},
	Skip:         false,

	Width:       100,
	Height:      20,
	SetupConfig: func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		for i := range 40 {
			shell.CreateFileAndAdd(fmt.Sprintf("file%02d", i+1), "one\ntwo\nthree\n")
		}
		shell.Commit("first commit")
		for i := range 40 {
			shell.UpdateFileAndAdd(fmt.Sprintf("file%02d", i+1), "one\nTWO\nthree\n")
		}
		shell.Commit("touch every file")
		shell.EmptyCommit("nothing to see here")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Commits().
			Focus().
			Lines(
				Contains("nothing to see here").IsSelected(),
				Contains("touch every file"),
				Contains("first commit"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden().
			PressEscape()

		t.Views().Commits().
			IsFocused().
			SelectNextItem()

		t.Views().Main().Content(Contains("40 files changed"))

		t.Views().Commits().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive()
	},
})
View Source
var SelectDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view selects the first visible change line, and the arrow keys move the selection",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive().
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("+THREE"),
			).
			Press(keys.Universal.PrevItem).
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Universal.GotoTop).
			SelectedLines(
				Contains("diff --git a/file1 b/file1"),
			).
			Press(keys.Universal.Return)

		t.Views().Files().
			IsFocused()
	},
})
View Source
var SelectHunkBelowLastChange = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Toggling hunk selection while below the last change selects the last change block",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nthree\nfour\nfive\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains(" five")).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-two"),
				Contains("+TWO"),
			)
	},
})
View Source
var SelectHunkInDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Toggle hunk selection in the focused main view, and step from hunk to hunk",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nFOUR\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-three"),
				Contains("-four"),
				Contains("+THREE"),
				Contains("+FOUR"),
			).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			Press(keys.Universal.PrevItem).
			SelectedLines(
				Contains("-three"),
				Contains("-four"),
				Contains("+THREE"),
				Contains("+FOUR"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-three"),
			)
	},
})
View Source
var SelectHunkOnFocusingMainView = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "When hunk mode is the default, focusing the main view selects the first whole change block",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
			).
			Press(keys.Universal.Return)

		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Click(0, 14).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			Click(0, 15).
			SelectedLines(
				Contains("+NINE"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			Click(0, 12).
			SelectedLines(
				Contains(" seven"),
			)
	},
})
View Source
var SelectInADiffReadInPart = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view over a diff longer than the part of it that has been read still shows a selection",
	ExtraCmdArgs: []string{},
	Skip:         false,

	Width:       100,
	Height:      20,
	SetupConfig: func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 600)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%03d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one big commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsActive()
	},
})
View Source
var SelectLineWhenWholeFileIsOneHunk = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Hunk mode falls back to a single line for a file that is one solid block of changes, rather than selecting all of it",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {
		shell.EmptyCommit("one")
		shell.CreateFileAndAdd("added", "one\ntwo\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("added").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+one"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("+one"),
				Contains("+two"),
				Contains("+three"),
			)
	},
})
View Source
var SelectNextChangeAfterStaging = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "After staging from the focused main view the selection lands on the change that took the place of the one staged",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nADD1\nADD2\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+ADD1"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("+ADD2"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("-nine"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			PressPrimaryAction().
			Tap(func() {
				t.Views().Files().Lines(
					Contains("M  file1"),
				)
			})
	},
})
View Source
var SelectNextChangeAfterUnstaging = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Taking one line of a staged modification back out of the index moves on to the line that replaced it, in the pane the staged side ended up in",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "c0\na1\na2\na3\nc1\nc2\noldB\nc3\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "c0\nc1\nc2\nnewB\nc3\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("-a1"),
			).
			NavigateToLine(Contains("-oldB")).
			PressPrimaryAction()

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+newB"),
			)
	},
})
View Source
var SelectNextDeletionAfterStagingOne = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Staging one deletion in the middle of a block of them moves on to the next, not back to the block's first line",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "keep1\nd1\nd2\nd3\nd4\nkeep2\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "keep1\nkeep2\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-d1"),
			).
			Press(keys.Universal.NextItem).
			Press(keys.Universal.NextItem).
			SelectedLines(
				Contains("-d3"),
			).
			PressPrimaryAction().
			SelectedLines(
				Contains("-d4"),
			)
	},
})
View Source
var SelectVisibleChangeOnFocusingMainView = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view selects a change that is already on screen, leaving the diff where it is",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffContextSize = 20
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 60)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		lines[4] = strings.ToUpper(lines[4])
		lines[54] = strings.ToUpper(lines[54])
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain)

		t.Views().Main().
			OriginY(4).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.FocusMainView)
			}).
			IsFocused().
			SelectedLines(
				Contains("-line05"),
			).
			OriginY(4).
			PressEscape()

		t.Views().Files().
			IsFocused().
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain).
			Press(keys.Universal.ScrollDownMain)

		t.Views().Main().
			OriginY(12).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.FocusMainView)
			}).
			IsFocused().
			SelectedLines(
				Contains(" line19"),
			).
			SelectedLineIdx(24).
			OriginY(12)
	},
})
View Source
var SelectVisibleHunkOnFocusingMainView = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Focusing the main view in hunk mode picks a block that begins on screen, leaving the diff where it is",
	ExtraCmdArgs: []string{},
	Skip:         false,
	Width:        120,
	Height:       30,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true

		cfg.GetUserConfig().Gui.ScrollHeight = 1
		cfg.GetUserConfig().Git.DiffContextSize = 20
	},
	SetupRepo: func(shell *Shell) {
		lines := make([]string, 80)
		for i := range lines {
			lines[i] = fmt.Sprintf("line%02d", i+1)
		}
		shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
		shell.Commit("one")

		for _, i := range []int{10, 20, 70} {
			lines[i-1] = strings.ToUpper(lines[i-1])
		}
		shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		scrollDown := func(lines int) {
			for range lines {
				t.Views().Files().Press(keys.Universal.ScrollDownMain)
			}
		}

		t.Views().Files().IsFocused()

		scrollDown(15)

		t.Views().Main().
			OriginY(15).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.FocusMainView)
			}).
			IsFocused().
			SelectedLines(
				Contains("-line20"),
				Contains("+LINE20"),
			).
			OriginY(15).
			PressEscape()

		scrollDown(11)

		t.Views().Main().
			OriginY(26).
			Tap(func() {
				t.Views().Files().Press(keys.Universal.FocusMainView)
			}).
			IsFocused().
			SelectedLines(
				Contains("-line20"),
				Contains("+LINE20"),
			).
			SelectedLineIdx(25).
			OriginY(26).
			PressEscape()

		t.Views().Main().
			Click(0, 0).
			IsFocused().
			SelectedLines(
				Contains("-line20"),
				Contains("+LINE20"),
			).
			OriginY(26)
	},
})
View Source
var SelectionCommandTooltipsFollowTheDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The tooltips of the selection commands describe what they do over the diff they are offered on",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\nTWO\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Select(Contains("Stage")).
			Tooltip(Equals("Toggle selection staged / unstaged.")).
			Select(Contains("Discard")).
			Tooltip(Contains("discard the change using `git reset`")).
			Cancel()

		t.Views().Main().PressEscape()

		t.Views().Commits().
			Focus().
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Select(Contains("Toggle lines in patch")).
			Tooltip(Equals("")).
			Select(Contains("Remove lines from commit")).
			Tooltip(Contains("runs an interactive rebase in the background")).
			Cancel()
	},
})
View Source
var SelectionCommandsOnlyWhereTheyApply = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The keybindings menu offers the commands that act on a diff selection only in a main view that has one",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Branches().
			Focus().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Tap(func() {
				t.Views().Menu().
					Content(DoesNotContain("Select hunks")).
					Content(DoesNotContain("Toggle range select")).
					Content(DoesNotContain("Go to next hunk")).
					Content(DoesNotContain("Go to next file"))
			}).
			Cancel()

		t.Views().Files().
			Focus().
			IsEmpty().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectionIsHidden().
			Press(keys.Universal.OptionMenu)

		t.ExpectPopup().Menu().
			Title(Equals("Keybindings")).
			Select(Contains("Select hunks")).
			Confirm()

		t.ExpectToast(Contains("There is nothing to select here"))
	},
})
View Source
var SelectionOverTheCustomPatch = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "The pane showing a custom patch keeps its selection across a refresh, its content being a diff like any other",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\n")
		shell.Commit("one")
		shell.UpdateFileAndAdd("file1", "one\nTWO\nthree\n")
		shell.Commit("two")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			NavigateToLine(Contains("two")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			PressPrimaryAction().
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			Title(Equals("Custom patch")).
			SelectionIsActive().
			Tap(func() {
				t.GlobalPress(keys.Universal.Refresh)
			}).
			SelectionIsActive()
	},
})
View Source
var ShowTheTabSwitchedToLast = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Switching tabs twice in rapid succession leaves the main view showing the second tab's content",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\n")
		shell.Commit("one")
		shell.UpdateFile("file1", "ONE\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Worktrees().
			Focus().
			Lines(
				Contains("(main worktree)").IsSelected(),
			)

		t.Views().Main().
			Content(Contains("Path:"))

		t.Views().Worktrees().
			PressRapidly(keys.Universal.PrevTab, keys.Universal.NextTab).
			IsFocused()

		t.Views().Main().
			Content(Contains("Path:"))
	},
})

Both tab switches are handled before the next layout. Switching to the Files tab asks for the file's diff, whose task is only created after the layout; switching back to the Worktrees tab asks for the worktree's details, whose task is created right away. The main view has to show what was asked for last.

View Source
var StageDeletedFile = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Acting on the whole of a file's block in a directory's diff acts on the file: staging a deletion, and unstaging an addition",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("fileA", "a\n")
		shell.CreateFileAndAdd("fileB", "b1\nb2\n")
		shell.Commit("one")

		shell.UpdateFile("fileA", "a\nfromA\n")
		shell.DeleteFile("fileB")
		shell.CreateFileAndAdd("fileC", "c1\nc2\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("▼ /").IsSelected(),
				Contains(" M fileA"),
				Contains(" D fileB"),
				Contains("A  fileC"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("-b1")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("-b2")).
			SelectedLines(
				Contains("-b1"),
				Contains("-b2"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("▼ /"),
			Contains(" M fileA"),
			Contains("D  fileB"),
			Contains("A  fileC"),
		)

		t.Views().Main().
			IsFocused().
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			NavigateToLine(Contains("+c1")).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+c2")).
			SelectedLines(
				Contains("+c1"),
				Contains("+c2"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("▼ /"),
			Contains(" M fileA"),
			Contains("D  fileB"),
			Contains("?? fileC"),
		)
	},
})
View Source
var StageDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage a line and a hunk of the working tree's diff from the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nADD1\nADD2\nthree\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+ADD1"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("MM file1"),
		)
		t.Views().Secondary().
			ContainsLines(
				Contains("+ADD1"),
			).
			Content(DoesNotContain("+ADD2"))
		t.Views().Main().
			Content(DoesNotContain("+ADD1")).
			ContainsLines(
				Contains("+ADD2"),
			)

		t.Views().Main().
			IsFocused().
			NavigateToLine(Contains("-nine")).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			PressPrimaryAction()

		t.Views().Secondary().ContainsLines(
			Contains("-nine"),
			Contains("+NINE"),
		)
		t.Views().Main().Content(DoesNotContain("NINE"))
	},
})
View Source
var StageDiffLinesOfAPathWithASpace = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage a line of a file whose path contains a space from the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {

		shell.CreateFileAndAdd("my file", "one\ntwo\nthree\n")
		shell.Commit("one")

		shell.UpdateFile("my file", "one\nADD1\nADD2\ntwo\nthree\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("my file").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+ADD1"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("MM my file"),
		)
		t.Views().Secondary().
			ContainsLines(
				Contains("+ADD1"),
			).
			Content(DoesNotContain("+ADD2"))
		t.Views().Main().
			Content(DoesNotContain("+ADD1")).
			ContainsLines(
				Contains("+ADD2"),
			)
	},
})
View Source
var StageHunksWithRapidKeypresses = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage two hunks from the focused main view with two space presses in rapid succession",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = true
	},
	SetupRepo: func(shell *Shell) {

		shell.CreateFileAndAdd("file1", "1\n2\na\nb\nc\nd\ne\nf\ng\n3\n4\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "1b\n2b\na\nb\nc\nd\ne\nf\ng\n3b\n4b\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			PressRapidly(keys.Universal.Select, keys.Universal.Select)

		t.Views().Files().Lines(
			Contains("M  file1"),
		)
		t.Views().Secondary().
			Title(Equals("Staged changes")).
			ContainsLines(
				Contains("+1b"),
				Contains("+2b"),
			).
			ContainsLines(
				Contains("+3b"),
				Contains("+4b"),
			)
	},
})

The second space is pressed before the diff the first one changed has re-rendered. The selection only moves to the next hunk once that render arrives, so until then it still covers lines that are no longer in the diff. The second press has to wait for the render rather than act on those lines.

View Source
var StagePartialBlockOfChangesFirstLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage only the first few lines of a block of consecutive changes",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			PressEnter()

		t.Views().Main().
			IsFocused().
			ContainsLines(
				Contains(" 1"),
				Contains("-2"),
				Contains("-3"),
				Contains("-4"),
				Contains("-5"),
				Contains("-6"),
				Contains("-7"),
				Contains("+2b"),
				Contains("+3b"),
				Contains("+4b"),
				Contains("+5b"),
				Contains("+6b"),
				Contains("+7b"),
				Contains(" 8"),
			).
			SelectedLines(Contains("-2")).
			PressPrimaryAction().
			SelectedLines(Contains("-3")).
			PressPrimaryAction().
			NavigateToLine(Contains("+2b")).
			PressPrimaryAction().
			SelectedLines(Contains("+3b")).
			PressPrimaryAction()

		t.Views().Secondary().
			ContainsLines(
				Contains(" 1"),
				Contains("-2"),
				Contains("-3"),
				Contains("+2b"),
				Contains("+3b"),
				Contains(" 4"),
				Contains(" 5"),
				Contains(" 6"),
			)
	},
})
View Source
var StagePartialBlockOfChangesLastLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage only the last few lines of a consecutive block of changes",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			PressEnter()

		t.Views().Main().
			IsFocused().
			ContainsLines(
				Contains(" 1"),
				Contains("-2"),
				Contains("-3"),
				Contains("-4"),
				Contains("-5"),
				Contains("-6"),
				Contains("-7"),
				Contains("+2b"),
				Contains("+3b"),
				Contains("+4b"),
				Contains("+5b"),
				Contains("+6b"),
				Contains("+7b"),
				Contains(" 8"),
			).
			NavigateToLine(Contains("-6")).
			PressPrimaryAction().
			SelectedLines(Contains("-7")).
			PressPrimaryAction().
			NavigateToLine(Contains("+6b")).
			PressPrimaryAction().
			SelectedLines(Contains("+7b")).
			PressPrimaryAction()

		t.Views().Secondary().
			ContainsLines(
				Contains(" 3"),
				Contains(" 4"),
				Contains(" 5"),
				Contains("-6"),
				Contains("-7"),
				Contains("+6b"),
				Contains("+7b"),
				Contains(" 8"),
			)
	},
})
View Source
var StagePartialBlockOfChangesMiddleLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage only the middle lines of a consecutive block of changes",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			PressEnter()

		t.Views().Main().
			IsFocused().
			ContainsLines(
				Contains(" 1"),
				Contains("-2"),
				Contains("-3"),
				Contains("-4"),
				Contains("-5"),
				Contains("-6"),
				Contains("-7"),
				Contains("+2b"),
				Contains("+3b"),
				Contains("+4b"),
				Contains("+5b"),
				Contains("+6b"),
				Contains("+7b"),
				Contains(" 8"),
			).
			NavigateToLine(Contains("-4")).
			PressPrimaryAction().
			SelectedLines(Contains("-5")).
			PressPrimaryAction().
			NavigateToLine(Contains("+4b")).
			PressPrimaryAction().
			SelectedLines(Contains("+5b")).
			PressPrimaryAction()

		t.Views().Secondary().
			ContainsLines(
				Contains(" 1"),
				Contains(" 2"),
				Contains(" 3"),
				Contains("-4"),
				Contains("-5"),
				Contains(" 6"),
				Contains(" 7"),
				Contains("+4b"),
				Contains("+5b"),
				Contains(" 8"),
			)
	},
})
View Source
var StageRangeSpanningFiles = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Stage a range reaching from one file's diff into another's, in a directory's focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("fileA", "a\n")
		shell.CreateFileAndAdd("fileB", "b\n")
		shell.CreateFileAndAdd("fileC", "c\n")
		shell.Commit("one")

		shell.UpdateFile("fileA", "a\nfromA\n")
		shell.UpdateFile("fileB", "b\nfromB\n")
		shell.UpdateFile("fileC", "c\nfromC\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("▼ /").IsSelected(),
				Contains(" M fileA"),
				Contains(" M fileB"),
				Contains(" M fileC"),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+fromA"),
			).
			Press(keys.Universal.ToggleRangeSelect).
			NavigateToLine(Contains("+fromB")).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("▼ /"),
			Contains("M  fileA"),
			Contains("M  fileB"),
			Contains(" M fileC"),
		)
	},
})
View Source
var StageUnderConformingDiffRenderer = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A diff renderer that announces the metadata protocol is taken at its word, so its diff is what stays on screen when the main view is focused",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Command: `printf '\033]1717;1\007RENDERED BY ME\n'; cat`},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().IsFocused()

		t.Views().Main().Content(Contains("RENDERED BY ME"))

		t.Views().Files().Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(Contains("RENDERED BY ME")).
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
			).
			PressPrimaryAction()

		t.Views().Secondary().ContainsLines(
			Contains("-three"),
			Contains("+THREE"),
		)
	},
})
View Source
var StageUnderUnsupportedDiffRenderer = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "A diff renderer that says nothing about what it renders is replaced by git's own diff when the main view is focused, so the diff can still be staged from",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false

		cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{
			{Command: "cat -n"},
		}
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFile("file1", "one\ntwo\nTHREE\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			)
		t.Views().Main().Content(Contains("1  diff --git a/file1 b/file1"))

		t.Views().Files().Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			Content(DoesNotContain("1  diff --git")).
			SelectedLines(
				Contains("-three"),
			).
			Press(keys.Main.ToggleSelectHunk).
			SelectedLines(
				Contains("-three"),
				Contains("+THREE"),
			).
			PressPrimaryAction()

		t.Views().Secondary().ContainsLines(
			Contains("-three"),
			Contains("+THREE"),
		)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("-nine"),
				Contains("+NINE"),
			).
			PressPrimaryAction()

		t.Views().Files().Lines(
			Contains("M  file1"),
		)
	},
})
View Source
var StartPatchFromAnotherCommit = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Confirm replacing a custom patch when selecting lines from another commit",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(config *config.AppConfig) {
		config.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "file1 content")
		shell.Commit("first commit")
		shell.CreateFileAndAdd("file2", "file2 content")
		shell.Commit("second commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().
			Focus().
			Lines(
				Contains("second commit").IsSelected(),
				Contains("first commit"),
			).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file2").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file2 content")).
			PressPrimaryAction()

		t.Views().Information().Content(Contains("Building patch"))
		t.Views().Secondary().Content(Contains("file2"))

		t.Views().Main().PressEscape()
		t.Views().CommitFiles().IsFocused().PressEscape()
		t.Views().Commits().
			IsFocused().
			NavigateToLine(Contains("first commit")).
			PressEnter()

		t.Views().CommitFiles().
			IsFocused().
			Lines(
				Contains("file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(Contains("+file1 content")).
			PressPrimaryAction()

		t.ExpectPopup().Confirmation().
			Title(Contains("Discard patch")).
			Content(Contains("You can only build a patch from one commit/stash-entry at a time. Discard current patch?")).
			Confirm()

		t.Views().Secondary().Content(Contains("file1").DoesNotContain("file2"))
	},
})
View Source
var UnstageDiffLines = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Take a line back out of the index from the staged half of the focused main view",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
		shell.Commit("one")

		shell.UpdateFileAndAdd("file1", "one\nSTAGED1\ntwo\nthree\nfour\nfive\nsix\nseven\nSTAGED2\neight\nnine\nten\n")
		shell.UpdateFile("file1", "one\nSTAGED1\ntwo\nthree\nUNSTAGED\nfour\nfive\nsix\nseven\nSTAGED2\neight\nnine\nten\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Files().
			IsFocused().
			Lines(
				Contains("MM file1").IsSelected(),
			).
			Press(keys.Universal.FocusMainView)

		t.Views().Main().
			IsFocused().
			SelectedLines(
				Contains("+UNSTAGED"),
			).
			Press(keys.Universal.TogglePanel)

		t.Views().Secondary().
			IsFocused().
			SelectedLines(
				Contains("+STAGED1"),
			).
			PressPrimaryAction()

		t.Views().Secondary().
			Content(DoesNotContain("+STAGED1")).
			ContainsLines(
				Contains("+STAGED2"),
			)
		t.Views().Main().ContainsLines(
			Contains("+STAGED1"),
		)
	},
})
View Source
var WrapOnlyTheDiff = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Turning wrapping off for diffs leaves everything else the main view shows wrapped",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig: func(cfg *config.AppConfig) {
		cfg.GetUserConfig().Gui.WrapLinesInDiffView = false
	},
	SetupRepo: func(shell *Shell) {
		shell.CreateFileAndAdd("file1", "one\n")
		shell.Commit(longLine)

		shell.UpdateFile("file1", "one\n"+longLine+"\n")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {

		t.Views().Files().
			IsFocused().
			Tap(func() {
				t.Views().Main().ContainsViewLines(Contains("start").Contains("end"))
			})

		t.Views().Branches().
			Focus()

		t.Views().Main().
			ContainsViewLines(Contains("end").DoesNotContain("start"))
	},
})

Functions

This section is empty.

Types

This section is empty.

Source Files

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL