github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/pr/comment/comment_test.go (about) 1 package comment 2 3 import ( 4 "bytes" 5 "fmt" 6 "net/http" 7 "os" 8 "path/filepath" 9 "testing" 10 11 "github.com/ungtb10d/cli/v2/api" 12 "github.com/ungtb10d/cli/v2/internal/browser" 13 "github.com/ungtb10d/cli/v2/internal/ghrepo" 14 "github.com/ungtb10d/cli/v2/pkg/cmd/pr/shared" 15 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 16 "github.com/ungtb10d/cli/v2/pkg/httpmock" 17 "github.com/ungtb10d/cli/v2/pkg/iostreams" 18 "github.com/google/shlex" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 func TestNewCmdComment(t *testing.T) { 24 tmpFile := filepath.Join(t.TempDir(), "my-body.md") 25 err := os.WriteFile(tmpFile, []byte("a body from file"), 0600) 26 require.NoError(t, err) 27 28 tests := []struct { 29 name string 30 input string 31 stdin string 32 output shared.CommentableOptions 33 wantsErr bool 34 }{ 35 { 36 name: "no arguments", 37 input: "", 38 output: shared.CommentableOptions{ 39 Interactive: true, 40 InputType: 0, 41 Body: "", 42 }, 43 wantsErr: false, 44 }, 45 { 46 name: "two arguments", 47 input: "1 2", 48 output: shared.CommentableOptions{}, 49 wantsErr: true, 50 }, 51 { 52 name: "pr number", 53 input: "1", 54 output: shared.CommentableOptions{ 55 Interactive: true, 56 InputType: 0, 57 Body: "", 58 }, 59 wantsErr: false, 60 }, 61 { 62 name: "pr url", 63 input: "https://github.com/OWNER/REPO/pull/12", 64 output: shared.CommentableOptions{ 65 Interactive: true, 66 InputType: 0, 67 Body: "", 68 }, 69 wantsErr: false, 70 }, 71 { 72 name: "pr branch", 73 input: "branch-name", 74 output: shared.CommentableOptions{ 75 Interactive: true, 76 InputType: 0, 77 Body: "", 78 }, 79 wantsErr: false, 80 }, 81 { 82 name: "body flag", 83 input: "1 --body test", 84 output: shared.CommentableOptions{ 85 Interactive: false, 86 InputType: shared.InputTypeInline, 87 Body: "test", 88 }, 89 wantsErr: false, 90 }, 91 { 92 name: "body from stdin", 93 input: "1 --body-file -", 94 stdin: "this is on standard input", 95 output: shared.CommentableOptions{ 96 Interactive: false, 97 InputType: shared.InputTypeInline, 98 Body: "this is on standard input", 99 }, 100 wantsErr: false, 101 }, 102 { 103 name: "body from file", 104 input: fmt.Sprintf("1 --body-file '%s'", tmpFile), 105 output: shared.CommentableOptions{ 106 Interactive: false, 107 InputType: shared.InputTypeInline, 108 Body: "a body from file", 109 }, 110 wantsErr: false, 111 }, 112 { 113 name: "editor flag", 114 input: "1 --editor", 115 output: shared.CommentableOptions{ 116 Interactive: false, 117 InputType: shared.InputTypeEditor, 118 Body: "", 119 }, 120 wantsErr: false, 121 }, 122 { 123 name: "web flag", 124 input: "1 --web", 125 output: shared.CommentableOptions{ 126 Interactive: false, 127 InputType: shared.InputTypeWeb, 128 Body: "", 129 }, 130 wantsErr: false, 131 }, 132 { 133 name: "body and body-file flags", 134 input: "1 --body 'test' --body-file 'test-file.txt'", 135 output: shared.CommentableOptions{}, 136 wantsErr: true, 137 }, 138 { 139 name: "editor and web flags", 140 input: "1 --editor --web", 141 output: shared.CommentableOptions{}, 142 wantsErr: true, 143 }, 144 { 145 name: "editor and body flags", 146 input: "1 --editor --body test", 147 output: shared.CommentableOptions{}, 148 wantsErr: true, 149 }, 150 { 151 name: "web and body flags", 152 input: "1 --web --body test", 153 output: shared.CommentableOptions{}, 154 wantsErr: true, 155 }, 156 { 157 name: "editor, web, and body flags", 158 input: "1 --editor --web --body test", 159 output: shared.CommentableOptions{}, 160 wantsErr: true, 161 }, 162 } 163 164 for _, tt := range tests { 165 t.Run(tt.name, func(t *testing.T) { 166 ios, stdin, _, _ := iostreams.Test() 167 ios.SetStdoutTTY(true) 168 ios.SetStdinTTY(true) 169 ios.SetStderrTTY(true) 170 171 if tt.stdin != "" { 172 _, _ = stdin.WriteString(tt.stdin) 173 } 174 175 f := &cmdutil.Factory{ 176 IOStreams: ios, 177 Browser: &browser.Stub{}, 178 } 179 180 argv, err := shlex.Split(tt.input) 181 assert.NoError(t, err) 182 183 var gotOpts *shared.CommentableOptions 184 cmd := NewCmdComment(f, func(opts *shared.CommentableOptions) error { 185 gotOpts = opts 186 return nil 187 }) 188 cmd.Flags().BoolP("help", "x", false, "") 189 190 cmd.SetArgs(argv) 191 cmd.SetIn(&bytes.Buffer{}) 192 cmd.SetOut(&bytes.Buffer{}) 193 cmd.SetErr(&bytes.Buffer{}) 194 195 _, err = cmd.ExecuteC() 196 if tt.wantsErr { 197 assert.Error(t, err) 198 return 199 } 200 201 assert.NoError(t, err) 202 assert.Equal(t, tt.output.Interactive, gotOpts.Interactive) 203 assert.Equal(t, tt.output.InputType, gotOpts.InputType) 204 assert.Equal(t, tt.output.Body, gotOpts.Body) 205 }) 206 } 207 } 208 209 func Test_commentRun(t *testing.T) { 210 tests := []struct { 211 name string 212 input *shared.CommentableOptions 213 httpStubs func(*testing.T, *httpmock.Registry) 214 stdout string 215 stderr string 216 }{ 217 { 218 name: "interactive editor", 219 input: &shared.CommentableOptions{ 220 Interactive: true, 221 InputType: 0, 222 Body: "", 223 224 InteractiveEditSurvey: func(string) (string, error) { return "comment body", nil }, 225 ConfirmSubmitSurvey: func() (bool, error) { return true, nil }, 226 }, 227 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 228 mockCommentCreate(t, reg) 229 }, 230 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n", 231 }, 232 { 233 name: "interactive editor with edit last", 234 input: &shared.CommentableOptions{ 235 Interactive: true, 236 InputType: 0, 237 Body: "", 238 EditLast: true, 239 240 InteractiveEditSurvey: func(string) (string, error) { return "comment body", nil }, 241 ConfirmSubmitSurvey: func() (bool, error) { return true, nil }, 242 }, 243 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 244 mockCommentUpdate(t, reg) 245 }, 246 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-111\n", 247 }, 248 { 249 name: "non-interactive web", 250 input: &shared.CommentableOptions{ 251 Interactive: false, 252 InputType: shared.InputTypeWeb, 253 Body: "", 254 255 OpenInBrowser: func(string) error { return nil }, 256 }, 257 stderr: "Opening github.com/OWNER/REPO/pull/123 in your browser.\n", 258 }, 259 { 260 name: "non-interactive web with edit last", 261 input: &shared.CommentableOptions{ 262 Interactive: false, 263 InputType: shared.InputTypeWeb, 264 Body: "", 265 EditLast: true, 266 267 OpenInBrowser: func(string) error { return nil }, 268 }, 269 stderr: "Opening github.com/OWNER/REPO/pull/123 in your browser.\n", 270 }, 271 { 272 name: "non-interactive editor", 273 input: &shared.CommentableOptions{ 274 Interactive: false, 275 InputType: shared.InputTypeEditor, 276 Body: "", 277 278 EditSurvey: func(string) (string, error) { return "comment body", nil }, 279 }, 280 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 281 mockCommentCreate(t, reg) 282 }, 283 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n", 284 }, 285 { 286 name: "non-interactive editor with edit last", 287 input: &shared.CommentableOptions{ 288 Interactive: false, 289 InputType: shared.InputTypeEditor, 290 Body: "", 291 EditLast: true, 292 293 EditSurvey: func(string) (string, error) { return "comment body", nil }, 294 }, 295 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 296 mockCommentUpdate(t, reg) 297 }, 298 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-111\n", 299 }, 300 { 301 name: "non-interactive inline", 302 input: &shared.CommentableOptions{ 303 Interactive: false, 304 InputType: shared.InputTypeInline, 305 Body: "comment body", 306 }, 307 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 308 mockCommentCreate(t, reg) 309 }, 310 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n", 311 }, 312 { 313 name: "non-interactive inline with edit last", 314 input: &shared.CommentableOptions{ 315 Interactive: false, 316 InputType: shared.InputTypeInline, 317 Body: "comment body", 318 EditLast: true, 319 }, 320 httpStubs: func(t *testing.T, reg *httpmock.Registry) { 321 mockCommentUpdate(t, reg) 322 }, 323 stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-111\n", 324 }, 325 } 326 for _, tt := range tests { 327 ios, _, stdout, stderr := iostreams.Test() 328 ios.SetStdoutTTY(true) 329 ios.SetStdinTTY(true) 330 ios.SetStderrTTY(true) 331 332 reg := &httpmock.Registry{} 333 defer reg.Verify(t) 334 if tt.httpStubs != nil { 335 tt.httpStubs(t, reg) 336 } 337 338 httpClient := func() (*http.Client, error) { return &http.Client{Transport: reg}, nil } 339 340 tt.input.IO = ios 341 tt.input.HttpClient = httpClient 342 tt.input.RetrieveCommentable = func() (shared.Commentable, ghrepo.Interface, error) { 343 return &api.PullRequest{ 344 Number: 123, 345 URL: "https://github.com/OWNER/REPO/pull/123", 346 Comments: api.Comments{Nodes: []api.Comment{ 347 {ID: "id1", Author: api.Author{Login: "octocat"}, URL: "https://github.com/OWNER/REPO/pull/123#issuecomment-111", ViewerDidAuthor: true}, 348 {ID: "id2", Author: api.Author{Login: "monalisa"}, URL: "https://github.com/OWNER/REPO/pull/123#issuecomment-222"}, 349 }}, 350 }, ghrepo.New("OWNER", "REPO"), nil 351 } 352 353 t.Run(tt.name, func(t *testing.T) { 354 err := shared.CommentableRun(tt.input) 355 assert.NoError(t, err) 356 assert.Equal(t, tt.stdout, stdout.String()) 357 assert.Equal(t, tt.stderr, stderr.String()) 358 }) 359 } 360 } 361 362 func mockCommentCreate(t *testing.T, reg *httpmock.Registry) { 363 reg.Register( 364 httpmock.GraphQL(`mutation CommentCreate\b`), 365 httpmock.GraphQLMutation(` 366 { "data": { "addComment": { "commentEdge": { "node": { 367 "url": "https://github.com/OWNER/REPO/pull/123#issuecomment-456" 368 } } } } }`, 369 func(inputs map[string]interface{}) { 370 assert.Equal(t, "comment body", inputs["body"]) 371 }), 372 ) 373 } 374 375 func mockCommentUpdate(t *testing.T, reg *httpmock.Registry) { 376 reg.Register( 377 httpmock.GraphQL(`mutation CommentUpdate\b`), 378 httpmock.GraphQLMutation(` 379 { "data": { "updateIssueComment": { "issueComment": { 380 "url": "https://github.com/OWNER/REPO/pull/123#issuecomment-111" 381 } } } }`, 382 func(inputs map[string]interface{}) { 383 assert.Equal(t, "id1", inputs["id"]) 384 assert.Equal(t, "comment body", inputs["body"]) 385 }), 386 ) 387 }