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