summaryrefslogtreecommitdiffstats
path: root/pkg/integration
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-07-31 22:43:36 +1000
committerGitHub <noreply@github.com>2023-07-31 22:43:36 +1000
commitb92c29405930458dbaa6dbe242eb4576e3d462f2 (patch)
tree51af990e03be5362649afc51c74fe936a995bf4e /pkg/integration
parent07d03df8df8fcd91b51efe9b036918569900d152 (diff)
parent9cc1d6528068d6552fd72461a2ad49987edd39da (diff)
Add automated demo recordings (#2853)
Diffstat (limited to 'pkg/integration')
-rw-r--r--pkg/integration/clients/go_test.go6
-rw-r--r--pkg/integration/clients/tui.go2
-rw-r--r--pkg/integration/components/commit_description_panel_driver.go2
-rw-r--r--pkg/integration/components/random.go212
-rw-r--r--pkg/integration/components/shell.go22
-rw-r--r--pkg/integration/components/test.go18
-rw-r--r--pkg/integration/components/test_driver.go18
-rw-r--r--pkg/integration/components/test_test.go6
-rw-r--r--pkg/integration/components/view_driver.go32
-rw-r--r--pkg/integration/tests/demo/bisect.go78
-rw-r--r--pkg/integration/tests/demo/cherry_pick.go94
-rw-r--r--pkg/integration/tests/demo/commit_and_push.go56
-rw-r--r--pkg/integration/tests/demo/interactive_rebase.go60
-rw-r--r--pkg/integration/tests/test_list.go5
-rw-r--r--pkg/integration/types/types.go4
15 files changed, 610 insertions, 5 deletions
diff --git a/pkg/integration/clients/go_test.go b/pkg/integration/clients/go_test.go
index 318c1af9d..851059e15 100644
--- a/pkg/integration/clients/go_test.go
+++ b/pkg/integration/clients/go_test.go
@@ -40,6 +40,12 @@ func TestIntegration(t *testing.T) {
return
}
+ // not running demoes right now. Arguably we should, but we'd need to
+ // strip away any artificial lag they use.
+ if test.IsDemo() {
+ return
+ }
+
t.Run(test.Name(), func(t *testing.T) {
t.Parallel()
err := f()
diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go
index 47f1a2dc2..904712037 100644
--- a/pkg/integration/clients/tui.go
+++ b/pkg/integration/clients/tui.go
@@ -19,7 +19,7 @@ import (
// This program lets you run integration tests from a TUI. See pkg/integration/README.md for more info.
-var SLOW_KEY_PRESS_DELAY = 300
+var SLOW_KEY_PRESS_DELAY = 600
func RunTUI() {
rootDir := utils.GetLazyRootDirectory()
diff --git a/pkg/integration/components/commit_description_panel_driver.go b/pkg/integration/components/commit_description_panel_driver.go
index e7ab13b33..993b1316f 100644
--- a/pkg/integration/components/commit_description_panel_driver.go
+++ b/pkg/integration/components/commit_description_panel_driver.go
@@ -20,7 +20,7 @@ func (self *CommitDescriptionPanelDriver) SwitchToSummary() *CommitMessagePanelD
}
func (self *CommitDescriptionPanelDriver) AddNewline() *CommitDescriptionPanelDriver {
- self.t.press(self.t.keys.Universal.Confirm)
+ self.t.pressFast(self.t.keys.Universal.Confirm)
return self
}
diff --git a/pkg/integration/components/random.go b/pkg/integration/components/random.go
new file mode 100644
index 000000000..cfd9d40ba
--- /dev/null
+++ b/pkg/integration/components/random.go
@@ -0,0 +1,212 @@
+package components
+
+var RandomCommitMessages = []string{
+ `Refactor HTTP client for better error handling`,
+ `Integrate pagination in user listings`,
+ `Fix incorrect type in updateUser function`,
+ `Create initial setup for postgres database`,
+ `Add unit tests for authentication service`,
+ `Improve efficiency of sorting algorithm in util package`,
+ `Resolve intermittent test failure in CartTest`,
+ `Introduce cache layer for product images`,
+ `Revamp User Interface of the settings page`,
+ `Remove deprecated uses of api endpoints`,
+ `Ensure proper escaping of SQL queries`,
+ `Implement feature flag for dark mode`,
+ `Add functionality for users to reset password`,
+ `Optimize performance of image loading on home screen`,
+ `Correct argument type in the sendEmail function`,
+ `Merge feature branch 'add-payment-gateway'`,
+ `Add validation to signup form fields`,
+ `Refactor User model to include middle name`,
+ `Update README with new setup instructions`,
+ `Extend session expiry time to 24 hours`,
+ `Implement rate limiting on login attempts`,
+ `Add sorting feature to product listing page`,
+ `Refactor logic in Lazygit Diff view`,
+ `Optimize Lazygit startup time`,
+ `Fix typos in documentation`,
+ `Move global variables to environment config`,
+ `Upgrade Rails version to 6.1.4`,
+ `Refactor user notifications system`,
+ `Implement user blocking functionality`,
+ `Improve Dockerfile for more efficient builds`,
+ `Introduce Redis for session management`,
+ `Ensure CSRF protection for all forms`,
+ `Implement bulk delete feature in admin panel`,
+ `Harden security of user password storage`,
+ `Resolve race condition in transaction handling`,
+ `Migrate legacy codebase to Typescript`,
+ `Update UX of password reset feature`,
+ `Add internationalization support for German`,
+ `Enhance logging in production environment`,
+ `Remove hardcoded values from payment module`,
+ `Introduce retry mechanism in network calls`,
+ `Handle edge case for zero quantity in cart`,
+ `Revamp error handling in user registration`,
+ `Replace deprecated lifecycle methods in React components`,
+ `Update styles according to new design guidelines`,
+ `Handle database connection failures gracefully`,
+ `Ensure atomicity of transactions in payment system`,
+ `Refactor session management using JWT`,
+ `Enhance user search with fuzzy matching`,
+ `Move constants to a separate config file`,
+ `Add TypeScript types to User module`,
+ `Implement automated backups for database`,
+ `Fix broken links on the help page`,
+ `Add end-to-end tests for checkout flow`,
+ `Add loading indicators to improve UX`,
+ `Improve accessibility of site navigation`,
+ `Refactor error messages for better clarity`,
+ `Enable gzip compression for faster page loads`,
+ `Set up CI/CD pipeline using GitHub actions`,
+ `Add a user-friendly 404 page`,
+ `Implement OAuth login with Google`,
+ `Resolve dependency conflicts in package.json`,
+ `Add proper alt text to all images for SEO`,
+ `Implement comment moderation feature`,
+ `Fix double encoding issue in URL parameters`,
+ `Resolve flickering issue in animation`,
+ `Update dependencies to latest stable versions`,
+ `Set proper cache headers for static assets`,
+ `Add structured data for better SEO`,
+ `Refactor to remove circular dependencies`,
+ `Add feature to report inappropriate content`,
+ `Implement mobile-friendly navigation menu`,
+ `Update privacy policy to comply with GDPR`,
+ `Fix memory leak issue in event listeners`,
+ `Improve form validation feedback for user`,
+ `Implement API versioning`,
+ `Improve resilience of system by adding circuit breaker`,
+ `Add sitemap.xml for better search engine indexing`,
+ `Set up performance monitoring with New Relic`,
+ `Introduce service worker for offline support`,
+ `Enhance email notifications with HTML templates`,
+ `Ensure all pages are responsive across devices`,
+ `Create helper functions to reduce code duplication`,
+ `Add 'remember me' feature to login`,
+ `Increase test coverage for User model`,
+ `Refactor error messages into a separate module`,
+ `Optimize images for faster loading`,
+ `Ensure correct HTTP status codes for all responses`,
+ `Implement auto-save feature in post editor`,
+ `Update user guide with new screenshots`,
+ `Implement load testing using Gatling`,
+ `Add keyboard shortcuts for commonly used actions`,
+ `Set up staging environment similar to production`,
+ `Ensure all forms use POST method for data submission`,
+ `Implement soft delete for user accounts`,
+ `Add Webpack for asset bundling`,
+ `Handle session timeout gracefully`,
+ `Remove unused code and libraries`,
+ `Integrate support for markdown in user posts`,
+ `Fix bug in timezone conversion.`,
+}
+
+type RandomFile struct {
+ Name string
+ Content string
+}
+
+var RandomFiles = []RandomFile{
+ {Name: `http_client.go`, Content: `package httpclient`},
+ {Name: `user_listings.go`, Content: `package listings`},
+ {Name: `user_service.go`, Content: `package service`},
+ {Name: `database_setup.sql`, Content: `CREATE TABLE`},
+ {Name: `authentication_test.go`, Content: `package auth_test`},
+ {Name: `utils/sorting.go`, Content: `package utils`},
+ {Name: `tests/cart_test.go`, Content: `package tests`},
+ {Name: `cache/product_images.go`, Content: `package cache`},
+ {Name: `ui/settings_page.jsx`, Content: `import React`},
+ {Name: `api/deprecated_endpoints.go`, Content: `package api`},
+ {Name: `db/sql_queries.go`, Content: `package db`},
+ {Name: `features/dark_mode.go`, Content: `package features`},
+ {Name: `user/password_reset.go`, Content: `package user`},
+ {Name: `performance/image_loading.go`, Content: `package performance`},
+ {Name: `email/send_email.go`, Content: `package email`},
+ {Name: `merge/payment_gateway.go`, Content: `package merge`},
+ {Name: `forms/signup_validation.go`, Content: `package forms`},
+ {Name: `models/user.go`, Content: `package models`},
+ {Name: `README.md`, Content: `# Project`},
+ {Name: `config/session.go`, Content: `package config`},
+ {Name: `security/rate_limit.go`, Content: `package security`},
+ {Name: `product/sort_list.go`, Content: `package product`},
+ {Name: `lazygit/diff_view.go`, Content: `package lazygit`},
+ {Name: `performance/lazygit.go`, Content: `package performance`},
+ {Name: `docs/documentation.go`, Content: `package docs`},
+ {Name: `config/global_variables.go`, Content: `package config`},
+ {Name: `Gemfile`, Content: `source 'https://rubygems.org'`},
+ {Name: `notification/user_notification.go`, Content: `package notification`},
+ {Name: `user/blocking.go`, Content: `package user`},
+ {Name: `Dockerfile`, Content: `FROM ubuntu:18.04`},
+ {Name: `redis/session_manager.go`, Content: `package redis`},
+ {Name: `security/csrf_protection.go`, Content: `package security`},
+ {Name: `admin/bulk_delete.go`, Content: `package admin`},
+ {Name: `security/password_storage.go`, Content: `package security`},
+ {Name: `transactions/transaction_handling.go`, Content: `package transactions`},
+ {Name: `migrations/typescript_migration.go`, Content: `package migrations`},
+ {Name: `ui/password_reset.jsx`, Content: `import React`},
+ {Name: `i18n/german.go`, Content: `package i18n`},
+ {Name: `logging/production_logging.go`, Content: `package logging`},
+ {Name: `payment/hardcoded_values.go`, Content: `package payment`},
+ {Name: `network/retry.go`, Content: `package network`},
+ {Name: `cart/zero_quantity.go`, Content: `package cart`},
+ {Name: `registration/error_handling.go`, Content: `package registration`},
+ {Name: `components/deprecated_methods.jsx`, Content: `import React`},
+ {Name: `styles/new_guidelines.css`, Content: `.class {}`},
+ {Name: `db/connection_failure.go`, Content: `package db`},
+ {Name: `payment/transaction_atomicity.go`, Content: `package payment`},
+ {Name: `session/jwt_management.go`, Content: `package session`},
+ {Name: `search/fuzzy_matching.go`, Content: `package search`},
+ {Name: `config/constants.go`, Content: `package config`},
+ {Name: `models/user_types.go`, Content: `package models`},
+ {Name: `backup/database_backup.go`, Content: `package backup`},
+ {Name: `help_page/links.go`, Content: `package help_page`},
+ {Name: `tests/checkout_test.sql`, Content: `DELETE ALL TABLES;`},
+ {Name: `ui/loading_indicator.jsx`, Content: `import React`},
+ {Name: `navigation/site_navigation.go`, Content: `package navigation`},
+ {Name: `error/error_messages.go`, Content: `package error`},
+ {Name: `performance/gzip_compression.go`, Content: `package performance`},
+ {Name: `.github/workflows/ci.yml`, Content: `name: CI`},
+ {Name: `pages/404.html`, Content: `<html></html>`},
+ {Name: `oauth/google_login.go`, Content: `package oauth`},
+ {Name: `package.json`, Content: `{}`},
+ {Name: `seo/alt_text.go`, Content: `package seo`},
+ {Name: `moderation/comment_moderation.go`, Content: `package moderation`},
+ {Name: `url/double_encoding.go`, Content: `package url`},
+ {Name: `animation/flickering.go`, Content: `package animation`},
+ {Name: `upgrade_dependencies.sh`, Content: `#!/bin/sh`},
+ {Name: `security/csrf_protection2.go`, Content: `package security`},
+ {Name: `admin/bulk_delete2.go`, Content: `package admin`},
+ {Name: `security/password_storage2.go`, Content: `package security`},
+ {Name: `transactions/transaction_handling2.go`, Content: `package transactions`},
+ {Name: `migrations/typescript_migration2.go`, Content: `package migrations`},
+ {Name: `ui/password_reset2.jsx`, Content: `import React`},
+ {Name: `i18n/german2.go`, Content: `package i18n`},
+ {Name: `logging/production_logging2.go`, Content: `package logging`},
+ {Name: `payment/hardcoded_values2.go`, Content: `package payment`},
+ {Name: `network/retry2.go`, Content: `package network`},
+ {Name: `cart/zero_quantity2.go`, Content: `package cart`},
+ {Name: `registration/error_handling2.go`, Content: `package registration`},
+ {Name: `components/deprecated_methods2.jsx`, Content: `import React`},
+ {Name: `styles/new_guidelines2.css`, Content: `.class {}`},
+ {Name: `db/connection_failure2.go`, Content: `package db`},
+ {Name: `payment/transaction_atomicity2.go`, Content: `package payment`},
+ {Name: `session/jwt_management2.go`, Content: `package session`},
+ {Name: `search/fuzzy_matching2.go`, Content: `package search`},
+ {Name: `config/constants2.go`, Content: `package config`},
+ {Name: `models/user_types2.go`, Content: `package models`},
+ {Name: `backup/database_backup2.go`, Content: `package backup`},
+ {Name: `help_page/links2.go`, Content: `package help_page`},
+ {Name: `tests/checkout_test2.go`, Content: `package tests`},
+ {Name: `ui/loading_indicator2.jsx`, Content: `import React`},
+ {Name: `navigation/site_navigation2.go`, Content: `package navigation`},
+ {Name: `error/error_messages2.go`, Content: `package error`},
+ {Name: `performance/gzip_compression2.go`, Content: `package performance`},
+ {Name: `.github/workflows/ci2.yml`, Content: `name: CI`},
+ {Name: `pages/4042.html`, Content: `<html></html>`},
+ {Name: `oauth/google_login2.go`, Content: `package oauth`},
+ {Name: `package2.json`, Content: `{}`},
+ {Name: `seo/alt_text2.go`, Content: `package seo`},
+ {Name: `moderation/comment_moderation2.go`, Content: `package moderation`},
+}
diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go
index 51fa2310b..7b0e9ddbf 100644
--- a/pkg/integration/components/shell.go
+++ b/pkg/integration/components/shell.go
@@ -74,6 +74,13 @@ func (self *Shell) RunShellCommand(cmdStr string) *Shell {
func (self *Shell) CreateFile(path string, content string) *Shell {
fullPath := filepath.Join(self.dir, path)
+
+ // create any required directories
+ dir := filepath.Dir(fullPath)
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ self.fail(fmt.Sprintf("error creating directory: %s\n%s", dir, err))
+ }
+
err := os.WriteFile(fullPath, []byte(content), 0o644)
if err != nil {
self.fail(fmt.Sprintf("error creating file: %s\n%s", fullPath, err))
@@ -195,6 +202,21 @@ func (self *Shell) CreateNCommitsStartingAt(n, startIndex int) *Shell {
return self
}
+// Only to be used in demos, because the list might change and we don't want
+// tests to break when it does.
+func (self *Shell) CreateNCommitsWithRandomMessages(n int) *Shell {
+ for i := 0; i < n; i++ {
+ file := RandomFiles[i]
+ self.CreateFileAndAdd(
+ file.Name,
+ file.Content,
+ ).
+ Commit(RandomCommitMessages[i])
+ }
+
+ return self
+}
+
func (self *Shell) SetConfig(key string, value string) *Shell {
self.RunCommand([]string{"git", "config", "--local", key, value})
return self
diff --git a/pkg/integration/components/test.go b/pkg/integration/components/test.go
index 2520ec47e..d24e20bd5 100644
--- a/pkg/integration/components/test.go
+++ b/pkg/integration/components/test.go
@@ -38,6 +38,7 @@ type IntegrationTest struct {
gitVersion GitVersionRestriction
width int
height int
+ isDemo bool
}
var _ integrationTypes.IntegrationTest = &IntegrationTest{}
@@ -63,6 +64,8 @@ type NewIntegrationTestArgs struct {
// If these are set, the test must be run in headless mode
Width int
Height int
+ // If true, this is not a test but a demo to be added to our docs
+ IsDemo bool
}
type GitVersionRestriction struct {
@@ -133,6 +136,7 @@ func NewIntegrationTest(args NewIntegrationTestArgs) *IntegrationTest {
gitVersion: args.GitVersion,
width: args.Width,
height: args.Height,
+ isDemo: args.IsDemo,
}
}
@@ -156,6 +160,10 @@ func (self *IntegrationTest) Skip() bool {
return self.skip
}
+func (self *IntegrationTest) IsDemo() bool {
+ return self.isDemo
+}
+
func (self *IntegrationTest) ShouldRunForGitVersion(version *git_commands.GitVersion) bool {
return self.gitVersion.shouldRunOnVersion(version)
}
@@ -178,9 +186,19 @@ func (self *IntegrationTest) Run(gui integrationTypes.GuiDriver) {
keys := gui.Keys()
testDriver := NewTestDriver(gui, shell, keys, KeyPressDelay())
+ if KeyPressDelay() > 0 {
+ // Setting caption to clear the options menu from whatever it starts with
+ testDriver.SetCaption("")
+ testDriver.SetCaptionPrefix("")
+ testDriver.Wait(1000)
+ }
+
self.run(testDriver, keys)
if KeyPressDelay() > 0 {
+ // Clear whatever caption there was so it doesn't linger
+ testDriver.SetCaption("")
+ testDriver.SetCaptionPrefix("")
// the dev would want to see the final state if they're running in slow mode
testDriver.Wait(2000)
}
diff --git a/pkg/integration/components/test_driver.go b/pkg/integration/components/test_driver.go
index 8ca3f1f70..80e4cb948 100644
--- a/pkg/integration/components/test_driver.go
+++ b/pkg/integration/components/test_driver.go
@@ -30,9 +30,17 @@ func NewTestDriver(gui integrationTypes.GuiDriver, shell *Shell, keys config.Key
// key is something like 'w' or '<space>'. It's best not to pass a direct value,
// but instead to go through the default user config to get a more meaningful key name
func (self *TestDriver) press(keyStr string) {
+ self.SetCaption(fmt.Sprintf("Pressing %s", keyStr))
+ self.gui.PressKey(keyStr)
self.Wait(self.pushKeyDelay)
+}
+// for use when typing or navigating, because in demos we want that to happen
+// faster
+func (self *TestDriver) pressFast(keyStr string) {
+ self.SetCaption("")
self.gui.PressKey(keyStr)
+ self.Wait(self.pushKeyDelay / 5)
}
// Should only be used in specific cases where you're doing something weird!
@@ -44,7 +52,7 @@ func (self *TestDriver) GlobalPress(keyStr string) {
func (self *TestDriver) typeContent(content string) {
for _, char := range content {
- self.press(string(char))
+ self.pressFast(string(char))
}
}
@@ -57,6 +65,14 @@ func (self *TestDriver) Wait(milliseconds int) {
time.Sleep(time.Duration(milliseconds) * time.Millisecond)
}
+func (self *TestDriver) SetCaption(caption string) {
+ self.gui.SetCaption(caption)
+}
+
+func (self *TestDriver) SetCaptionPrefix(prefix string) {
+ self.gui.SetCaptionPrefix(prefix)
+}
+
func (self *TestDriver) LogUI(message string) {
self.gui.LogUI(message)
}
diff --git a/pkg/integration/components/test_test.go b/pkg/integration/components/test_test.go
index d15f86b0c..b5c1c6055 100644
--- a/pkg/integration/components/test_test.go
+++ b/pkg/integration/components/test_test.go
@@ -63,6 +63,12 @@ func (self *fakeGuiDriver) View(viewName string) *gocui.View {
return nil
}
+func (self *fakeGuiDriver) SetCaption(string) {
+}
+
+func (self *fakeGuiDriver) SetCaptionPrefix(string) {
+}
+
func TestManualFailure(t *testing.T) {
test := NewIntegrationTest(NewIntegrationTestArgs{
Description: unitTestDescription,
diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go
index 8c2624dec..4e6cbd1d1 100644
--- a/pkg/integration/components/view_driver.go
+++ b/pkg/integration/components/view_driver.go
@@ -393,14 +393,24 @@ func (self *ViewDriver) Press(keyStr string) *ViewDriver {
return self
}
+// for use when typing or navigating, because in demos we want that to happen
+// faster
+func (self *ViewDriver) PressFast(keyStr string) *ViewDriver {
+ self.IsFocused()
+
+ self.t.pressFast(keyStr)
+
+ return self
+}
+
// i.e. pressing down arrow
func (self *ViewDriver) SelectNextItem() *ViewDriver {
- return self.Press(self.t.keys.Universal.NextItem)
+ return self.PressFast(self.t.keys.Universal.NextItem)
}
// i.e. pressing up arrow
func (self *ViewDriver) SelectPreviousItem() *ViewDriver {
- return self.Press(self.t.keys.Universal.PrevItem)
+ return self.PressFast(self.t.keys.Universal.PrevItem)
}
// i.e. pressing space
@@ -549,6 +559,24 @@ func (self *ViewDriver) FilterOrSearch(text string) *ViewDriver {
return self
}
+func (self *ViewDriver) SetCaption(caption string) *ViewDriver {
+ self.t.gui.SetCaption(caption)
+
+ return self
+}
+
+func (self *ViewDriver) SetCaptionPrefix(prefix string) *ViewDriver {
+ self.t.gui.SetCaptionPrefix(prefix)
+
+ return self
+}
+
+func (self *ViewDriver) Wait(milliseconds int) *ViewDriver {
+ self.t.Wait(milliseconds)
+
+ return self
+}
+
// for when you want to make some assertion unrelated to the current view
// without breaking the method chain
func (self *ViewDriver) Tap(f func()) *ViewDriver {
diff --git a/pkg/integration/tests/demo/bisect.go b/pkg/integration/tests/demo/bisect.go
new file mode 100644
index 000000000..d6191b6ea
--- /dev/null
+++ b/pkg/integration/tests/demo/bisect.go
@@ -0,0 +1,78 @@
+package demo
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var Bisect = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Interactive rebase",
+ ExtraCmdArgs: []string{"log"},
+ Skip: false,
+ IsDemo: true,
+ SetupConfig: func(config *config.AppConfig) {
+ // No idea why I had to use version 2: it should be using my own computer's
+ // font and the one iterm uses is version 3.
+ config.UserConfig.Gui.NerdFontsVersion = "2"
+ },
+ SetupRepo: func(shell *Shell) {
+ shell.CreateFile("my-file.txt", "myfile content")
+ shell.CreateFile("my-other-file.rb", "my-other-file content")
+
+ shell.CreateNCommitsWithRandomMessages(60)
+ shell.NewBranch("feature/demo")
+
+ shell.CloneIntoRemote("origin")
+
+ shell.SetBranchUpstream("feature/demo", "origin/feature/demo")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.SetCaptionPrefix("Git bisect")
+
+ markCommitAsBad := func() {
+ t.Views().Commits().
+ Press(keys.Commits.ViewBisectOptions)
+
+ t.ExpectPopup().Menu().Title(Equals("Bisect")).Select(MatchesRegexp(`Mark .* as bad`)).Confirm()
+ }
+
+ markCommitAsGood := func() {
+ t.Views().Commits().
+ Press(keys.Commits.ViewBisectOptions)
+
+ t.ExpectPopup().Menu().Title(Equals("Bisect")).Select(MatchesRegexp(`Mark .* as good`)).Confirm()
+ }
+
+ t.Views().Commits().
+ IsFocused().
+ Press(keys.Universal.NextScreenMode).
+ Tap(func() {
+ markCommitAsBad()
+
+ t.Views().Information().Content(Contains("Bisecting"))
+ }).
+ SelectedLine(Contains("<-- bad")).
+ NavigateToLine(Contains("Add TypeScript types to User module")).
+ Tap(markCommitAsGood).
+ SelectedLine(Contains("Add loading indicators to improve UX").Contains("<-- current")).
+ Tap(markCommitAsBad).
+ SelectedLine(Contains("Fix broken links on the help page").Contains("<-- current")).
+ Tap(markCommitAsGood).
+ SelectedLine(Contains("Add end-to-end tests for checkout flow").Contains("<-- current")).
+ Tap(markCommitAsBad).
+ Tap(func() {
+ t.Wait(2000)
+
+ t.ExpectPopup().Alert().Title(Equals("Bisect complete")).Content(MatchesRegexp("(?s).*Do you want to reset")).Confirm()
+ }).
+ SetCaptionPrefix("Inspect problematic commit").
+ Wait(500).
+ Press(keys.Universal.PrevScreenMode).
+ IsFocused().
+ Content(Contains("Add end-to-end tests for checkout flow")).
+ Wait(500).
+ PressEnter()
+
+ t.Views().Information().Content(DoesNotContain("Bisecting"))
+ },
+})
diff --git a/pkg/integration/tests/demo/cherry_pick.go b/pkg/integration/tests/demo/cherry_pick.go
new file mode 100644
index 000000000..5732a5b95
--- /dev/null
+++ b/pkg/integration/tests/demo/cherry_pick.go
@@ -0,0 +1,94 @@
+package demo
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Cherry pick",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ IsDemo: true,
+ SetupConfig: func(config *config.AppConfig) {
+ // No idea why I had to use version 2: it should be using my own computer's
+ // font and the one iterm uses is version 3.
+ config.UserConfig.Gui.NerdFontsVersion = "2"
+ },
+ SetupRepo: func(shell *Shell) {
+ shell.CreateNCommitsWithRandomMessages(50)
+
+ shell.
+ EmptyCommit("Fix bug in timezone conversion.").
+ NewBranch("hotfix/fix-bug").
+ NewBranch("feature/user-module").
+ Checkout("hotfix/fix-bug").
+ EmptyCommit("Integrate support for markdown in user posts").
+ EmptyCommit("Remove unused code and libraries").
+ Checkout("feature/user-module").
+ EmptyCommit("Handle session timeout gracefully").
+ EmptyCommit("Add Webpack for asset bundling").
+ Checkout("hotfix/fix-bug")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.SetCaptionPrefix("Cherry pick commits from another branch")
+
+ t.Views().Branches().
+ Focus().
+ Lines(
+ Contains("hotfix/fix-bug"),
+ Contains("feature/user-module"),
+ Contains("master"),
+ ).
+ SelectNextItem().
+ Wait(300).
+ PressEnter()
+
+ t.Views().SubCommits().
+ IsFocused().
+ TopLines(
+ Contains("Add Webpack for asset bundling").IsSelected(),
+ Contains("Handle session timeout gracefully"),
+ Contains("Fix bug in timezone conversion."),
+ ).
+ Press(keys.Commits.CherryPickCopy).
+ Tap(func() {
+ t.Views().Information().Content(Contains("1 commit copied"))
+ }).
+ SelectNextItem().
+ Press(keys.Commits.CherryPickCopy)
+
+ t.Views().Information().Content(Contains("2 commits copied"))
+
+ t.Views().Commits().
+ Focus().
+ TopLines(
+ Contains("Remove unused code and libraries").IsSelected(),
+ Contains("Integrate support for markdown in user posts"),
+ Contains("Fix bug in timezone conversion."),
+ ).
+ Press(keys.Commits.PasteCommits).
+ Tap(func() {
+ t.Wait(1000)
+ t.ExpectPopup().Alert().
+ Title(Equals("Cherry-pick")).
+ Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
+ Confirm()
+ }).
+ TopLines(
+ Contains("Add Webpack for asset bundling"),
+ Contains("Handle session timeout gracefully"),
+ Contains("Remove unused code and libraries"),
+ Contains("Integrate support for markdown in user posts"),
+ Contains("Fix bug in timezone conversion."),
+ ).
+ Tap(func() {
+ // we need to manually exit out of cherry pick mode
+ t.Views().Information().Content(Contains("2 commits copied"))
+ }).
+ PressEscape().
+ Tap(func() {
+ t.Views().Information().Content(DoesNotContain("commits copied"))
+ })
+ },
+})
diff --git a/pkg/integration/tests/demo/commit_and_push.go b/pkg/integration/tests/demo/commit_and_push.go
new file mode 100644
index 000000000..e897413e9
--- /dev/null
+++ b/pkg/integration/tests/demo/commit_and_push.go
@@ -0,0 +1,56 @@
+package demo
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var CommitAndPush = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Make a commit and push",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ IsDemo: true,
+ SetupConfig: func(config *config.AppConfig) {
+ // No idea why I had to use version 2: it should be using my own computer's
+ // font and the one iterm uses is version 3.
+ config.UserConfig.Gui.NerdFontsVersion = "2"
+ },
+ SetupRepo: func(shell *Shell) {
+ shell.CreateFile("my-file.txt", "myfile content")
+ shell.CreateFile("my-other-file.rb", "my-other-file content")
+
+ shell.CreateNCommitsWithRandomMessages(30)
+ shell.NewBranch("feature/demo")
+
+ shell.CloneIntoRemote("origin")
+
+ shell.SetBranchUpstream("feature/demo", "origin/feature/demo")
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.SetCaptionPrefix("Stage a file")
+
+ t.Views().Files().
+ IsFocused().
+ PressPrimaryAction().
+ SetCaptionPrefix("Commit our changes").
+ Press(keys.Files.CommitChanges)
+
+ t.ExpectPopup().CommitMessagePanel().
+ Type("my commit summary").
+ SwitchToDescription().
+ Type("my commit description").
+ SwitchToSummary().
+ Confirm()
+
+ t.Views().Commits().
+ TopLines(
+ Contains("my commit summary"),
+ )
+
+ t.SetCaptionPrefix("Push to the remote")
+
+ t.Views().Files().
+ IsFocused().
+ Press(keys.Universal.Push)
+ },
+})
diff --git a/pkg/integration/tests/demo/interactive_rebase.go b/pkg/integration/tests/demo/interactive_rebase.go
new file mode 100644
index 000000000..ca400a342
--- /dev/null
+++ b/