github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/pr/status/status_test.go (about) 1 package status 2 3 import ( 4 "bytes" 5 "io" 6 "net/http" 7 "regexp" 8 "strings" 9 "testing" 10 11 "github.com/MakeNowJust/heredoc" 12 "github.com/ungtb10d/cli/v2/context" 13 "github.com/ungtb10d/cli/v2/git" 14 "github.com/ungtb10d/cli/v2/internal/config" 15 "github.com/ungtb10d/cli/v2/internal/ghrepo" 16 "github.com/ungtb10d/cli/v2/internal/run" 17 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 18 "github.com/ungtb10d/cli/v2/pkg/httpmock" 19 "github.com/ungtb10d/cli/v2/pkg/iostreams" 20 "github.com/ungtb10d/cli/v2/test" 21 "github.com/google/shlex" 22 ) 23 24 func runCommand(rt http.RoundTripper, branch string, isTTY bool, cli string) (*test.CmdOut, error) { 25 ios, _, stdout, stderr := iostreams.Test() 26 ios.SetStdoutTTY(isTTY) 27 ios.SetStdinTTY(isTTY) 28 ios.SetStderrTTY(isTTY) 29 30 factory := &cmdutil.Factory{ 31 IOStreams: ios, 32 HttpClient: func() (*http.Client, error) { 33 return &http.Client{Transport: rt}, nil 34 }, 35 Config: func() (config.Config, error) { 36 return config.NewBlankConfig(), nil 37 }, 38 BaseRepo: func() (ghrepo.Interface, error) { 39 return ghrepo.New("OWNER", "REPO"), nil 40 }, 41 Remotes: func() (context.Remotes, error) { 42 return context.Remotes{ 43 { 44 Remote: &git.Remote{Name: "origin"}, 45 Repo: ghrepo.New("OWNER", "REPO"), 46 }, 47 }, nil 48 }, 49 Branch: func() (string, error) { 50 if branch == "" { 51 return "", git.ErrNotOnAnyBranch 52 } 53 return branch, nil 54 }, 55 GitClient: &git.Client{GitPath: "some/path/git"}, 56 } 57 58 cmd := NewCmdStatus(factory, nil) 59 cmd.PersistentFlags().StringP("repo", "R", "", "") 60 61 argv, err := shlex.Split(cli) 62 if err != nil { 63 return nil, err 64 } 65 cmd.SetArgs(argv) 66 67 cmd.SetIn(&bytes.Buffer{}) 68 cmd.SetOut(io.Discard) 69 cmd.SetErr(io.Discard) 70 71 _, err = cmd.ExecuteC() 72 return &test.CmdOut{ 73 OutBuf: stdout, 74 ErrBuf: stderr, 75 }, err 76 } 77 78 func initFakeHTTP() *httpmock.Registry { 79 return &httpmock.Registry{} 80 } 81 82 func TestPRStatus(t *testing.T) { 83 http := initFakeHTTP() 84 defer http.Verify(t) 85 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatus.json")) 86 87 output, err := runCommand(http, "blueberries", true, "") 88 if err != nil { 89 t.Errorf("error running command `pr status`: %v", err) 90 } 91 92 expectedPrs := []*regexp.Regexp{ 93 regexp.MustCompile(`#8.*\[strawberries\]`), 94 regexp.MustCompile(`#9.*\[apples\]`), 95 regexp.MustCompile(`#10.*\[blueberries\]`), 96 regexp.MustCompile(`#11.*\[figs\]`), 97 } 98 99 for _, r := range expectedPrs { 100 if !r.MatchString(output.String()) { 101 t.Errorf("output did not match regexp /%s/", r) 102 } 103 } 104 } 105 106 func TestPRStatus_reviewsAndChecks(t *testing.T) { 107 http := initFakeHTTP() 108 defer http.Verify(t) 109 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusChecks.json")) 110 111 output, err := runCommand(http, "blueberries", true, "") 112 if err != nil { 113 t.Errorf("error running command `pr status`: %v", err) 114 } 115 116 expected := []string{ 117 "✓ Checks passing + Changes requested ! Merge conflict status unknown", 118 "- Checks pending ✓ 2 Approved", 119 "× 1/3 checks failing - Review required ✓ No merge conflicts", 120 "✓ Checks passing × Merge conflicts", 121 } 122 123 for _, line := range expected { 124 if !strings.Contains(output.String(), line) { 125 t.Errorf("output did not contain %q: %q", line, output.String()) 126 } 127 } 128 } 129 130 func TestPRStatus_currentBranch_showTheMostRecentPR(t *testing.T) { 131 http := initFakeHTTP() 132 defer http.Verify(t) 133 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranch.json")) 134 135 output, err := runCommand(http, "blueberries", true, "") 136 if err != nil { 137 t.Errorf("error running command `pr status`: %v", err) 138 } 139 140 expectedLine := regexp.MustCompile(`#10 Blueberries are certainly a good fruit \[blueberries\]`) 141 if !expectedLine.MatchString(output.String()) { 142 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 143 return 144 } 145 146 unexpectedLines := []*regexp.Regexp{ 147 regexp.MustCompile(`#9 Blueberries are a good fruit \[blueberries\] - Merged`), 148 regexp.MustCompile(`#8 Blueberries are probably a good fruit \[blueberries\] - Closed`), 149 } 150 for _, r := range unexpectedLines { 151 if r.MatchString(output.String()) { 152 t.Errorf("output unexpectedly match regexp /%s/\n> output\n%s\n", r, output) 153 return 154 } 155 } 156 } 157 158 func TestPRStatus_currentBranch_defaultBranch(t *testing.T) { 159 http := initFakeHTTP() 160 defer http.Verify(t) 161 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranch.json")) 162 163 output, err := runCommand(http, "blueberries", true, "") 164 if err != nil { 165 t.Errorf("error running command `pr status`: %v", err) 166 } 167 168 expectedLine := regexp.MustCompile(`#10 Blueberries are certainly a good fruit \[blueberries\]`) 169 if !expectedLine.MatchString(output.String()) { 170 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 171 return 172 } 173 } 174 175 func TestPRStatus_currentBranch_defaultBranch_repoFlag(t *testing.T) { 176 http := initFakeHTTP() 177 defer http.Verify(t) 178 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranchClosedOnDefaultBranch.json")) 179 180 output, err := runCommand(http, "blueberries", true, "-R OWNER/REPO") 181 if err != nil { 182 t.Errorf("error running command `pr status`: %v", err) 183 } 184 185 expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\]`) 186 if expectedLine.MatchString(output.String()) { 187 t.Errorf("output not expected to match regexp /%s/\n> output\n%s\n", expectedLine, output) 188 return 189 } 190 } 191 192 func TestPRStatus_currentBranch_Closed(t *testing.T) { 193 http := initFakeHTTP() 194 defer http.Verify(t) 195 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranchClosed.json")) 196 197 output, err := runCommand(http, "blueberries", true, "") 198 if err != nil { 199 t.Errorf("error running command `pr status`: %v", err) 200 } 201 202 expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\] - Closed`) 203 if !expectedLine.MatchString(output.String()) { 204 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 205 return 206 } 207 } 208 209 func TestPRStatus_currentBranch_Closed_defaultBranch(t *testing.T) { 210 http := initFakeHTTP() 211 defer http.Verify(t) 212 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranchClosedOnDefaultBranch.json")) 213 214 output, err := runCommand(http, "blueberries", true, "") 215 if err != nil { 216 t.Errorf("error running command `pr status`: %v", err) 217 } 218 219 expectedLine := regexp.MustCompile(`There is no pull request associated with \[blueberries\]`) 220 if !expectedLine.MatchString(output.String()) { 221 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 222 return 223 } 224 } 225 226 func TestPRStatus_currentBranch_Merged(t *testing.T) { 227 http := initFakeHTTP() 228 defer http.Verify(t) 229 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranchMerged.json")) 230 231 output, err := runCommand(http, "blueberries", true, "") 232 if err != nil { 233 t.Errorf("error running command `pr status`: %v", err) 234 } 235 236 expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\] - Merged`) 237 if !expectedLine.MatchString(output.String()) { 238 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 239 return 240 } 241 } 242 243 func TestPRStatus_currentBranch_Merged_defaultBranch(t *testing.T) { 244 http := initFakeHTTP() 245 defer http.Verify(t) 246 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("./fixtures/prStatusCurrentBranchMergedOnDefaultBranch.json")) 247 248 output, err := runCommand(http, "blueberries", true, "") 249 if err != nil { 250 t.Errorf("error running command `pr status`: %v", err) 251 } 252 253 expectedLine := regexp.MustCompile(`There is no pull request associated with \[blueberries\]`) 254 if !expectedLine.MatchString(output.String()) { 255 t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output) 256 return 257 } 258 } 259 260 func TestPRStatus_blankSlate(t *testing.T) { 261 http := initFakeHTTP() 262 defer http.Verify(t) 263 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.StringResponse(`{"data": {}}`)) 264 265 output, err := runCommand(http, "blueberries", true, "") 266 if err != nil { 267 t.Errorf("error running command `pr status`: %v", err) 268 } 269 270 expected := ` 271 Relevant pull requests in OWNER/REPO 272 273 Current branch 274 There is no pull request associated with [blueberries] 275 276 Created by you 277 You have no open pull requests 278 279 Requesting a code review from you 280 You have no pull requests to review 281 282 ` 283 if output.String() != expected { 284 t.Errorf("expected %q, got %q", expected, output.String()) 285 } 286 } 287 288 func TestPRStatus_detachedHead(t *testing.T) { 289 http := initFakeHTTP() 290 defer http.Verify(t) 291 http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.StringResponse(`{"data": {}}`)) 292 293 output, err := runCommand(http, "", true, "") 294 if err != nil { 295 t.Errorf("error running command `pr status`: %v", err) 296 } 297 298 expected := ` 299 Relevant pull requests in OWNER/REPO 300 301 Current branch 302 There is no current branch 303 304 Created by you 305 You have no open pull requests 306 307 Requesting a code review from you 308 You have no pull requests to review 309 310 ` 311 if output.String() != expected { 312 t.Errorf("expected %q, got %q", expected, output.String()) 313 } 314 } 315 316 func Test_prSelectorForCurrentBranch(t *testing.T) { 317 rs, cleanup := run.Stub() 318 defer cleanup(t) 319 320 rs.Register(`git config --get-regexp \^branch\\.`, 0, heredoc.Doc(` 321 branch.Frederick888/main.remote git@github.com:Frederick888/playground.git 322 branch.Frederick888/main.merge refs/heads/main 323 `)) 324 325 repo := ghrepo.NewWithHost("octocat", "playground", "github.com") 326 rem := context.Remotes{ 327 &context.Remote{ 328 Remote: &git.Remote{Name: "origin"}, 329 Repo: repo, 330 }, 331 } 332 gitClient := &git.Client{GitPath: "some/path/git"} 333 prNum, headRef, err := prSelectorForCurrentBranch(gitClient, repo, "Frederick888/main", rem) 334 if err != nil { 335 t.Fatalf("prSelectorForCurrentBranch error: %v", err) 336 } 337 if prNum != 0 { 338 t.Errorf("expected prNum to be 0, got %q", prNum) 339 } 340 if headRef != "Frederick888:main" { 341 t.Errorf("expected headRef to be \"Frederick888:main\", got %q", headRef) 342 } 343 }