github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/workflow/view/view_test.go (about) 1 package view 2 3 import ( 4 "bytes" 5 "io" 6 "net/http" 7 "testing" 8 9 "github.com/MakeNowJust/heredoc" 10 "github.com/ungtb10d/cli/v2/internal/browser" 11 "github.com/ungtb10d/cli/v2/internal/ghrepo" 12 runShared "github.com/ungtb10d/cli/v2/pkg/cmd/run/shared" 13 "github.com/ungtb10d/cli/v2/pkg/cmd/workflow/shared" 14 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 15 "github.com/ungtb10d/cli/v2/pkg/httpmock" 16 "github.com/ungtb10d/cli/v2/pkg/iostreams" 17 "github.com/google/shlex" 18 "github.com/stretchr/testify/assert" 19 ) 20 21 func TestNewCmdView(t *testing.T) { 22 tests := []struct { 23 name string 24 cli string 25 tty bool 26 wants ViewOptions 27 wantsErr bool 28 }{ 29 { 30 name: "blank tty", 31 tty: true, 32 wants: ViewOptions{ 33 Prompt: true, 34 }, 35 }, 36 { 37 name: "blank nontty", 38 wantsErr: true, 39 }, 40 { 41 name: "arg tty", 42 cli: "123", 43 tty: true, 44 wants: ViewOptions{ 45 Selector: "123", 46 }, 47 }, 48 { 49 name: "arg nontty", 50 cli: "123", 51 wants: ViewOptions{ 52 Selector: "123", 53 Raw: true, 54 }, 55 }, 56 { 57 name: "web tty", 58 cli: "--web", 59 tty: true, 60 wants: ViewOptions{ 61 Prompt: true, 62 Web: true, 63 }, 64 }, 65 { 66 name: "web nontty", 67 cli: "-w 123", 68 wants: ViewOptions{ 69 Raw: true, 70 Web: true, 71 Selector: "123", 72 }, 73 }, 74 { 75 name: "yaml tty", 76 cli: "--yaml", 77 tty: true, 78 wants: ViewOptions{ 79 Prompt: true, 80 YAML: true, 81 }, 82 }, 83 { 84 name: "yaml nontty", 85 cli: "-y 123", 86 wants: ViewOptions{ 87 Raw: true, 88 YAML: true, 89 Selector: "123", 90 }, 91 }, 92 { 93 name: "ref tty", 94 cli: "--ref 456", 95 tty: true, 96 wantsErr: true, 97 }, 98 { 99 name: "ref nontty", 100 cli: "123 -r 456", 101 wantsErr: true, 102 }, 103 { 104 name: "yaml ref tty", 105 cli: "--yaml --ref 456", 106 tty: true, 107 wants: ViewOptions{ 108 Prompt: true, 109 YAML: true, 110 Ref: "456", 111 }, 112 }, 113 { 114 name: "yaml ref nontty", 115 cli: "123 -y -r 456", 116 wants: ViewOptions{ 117 Raw: true, 118 YAML: true, 119 Ref: "456", 120 Selector: "123", 121 }, 122 }, 123 } 124 125 for _, tt := range tests { 126 t.Run(tt.name, func(t *testing.T) { 127 ios, _, _, _ := iostreams.Test() 128 ios.SetStdinTTY(tt.tty) 129 ios.SetStdoutTTY(tt.tty) 130 131 f := &cmdutil.Factory{ 132 IOStreams: ios, 133 } 134 135 argv, err := shlex.Split(tt.cli) 136 assert.NoError(t, err) 137 138 var gotOpts *ViewOptions 139 cmd := NewCmdView(f, func(opts *ViewOptions) error { 140 gotOpts = opts 141 return nil 142 }) 143 cmd.SetArgs(argv) 144 cmd.SetIn(&bytes.Buffer{}) 145 cmd.SetOut(io.Discard) 146 cmd.SetErr(io.Discard) 147 148 _, err = cmd.ExecuteC() 149 if tt.wantsErr { 150 assert.Error(t, err) 151 return 152 } 153 154 assert.NoError(t, err) 155 assert.Equal(t, tt.wants.Selector, gotOpts.Selector) 156 assert.Equal(t, tt.wants.Ref, gotOpts.Ref) 157 assert.Equal(t, tt.wants.Web, gotOpts.Web) 158 assert.Equal(t, tt.wants.Prompt, gotOpts.Prompt) 159 assert.Equal(t, tt.wants.Raw, gotOpts.Raw) 160 assert.Equal(t, tt.wants.YAML, gotOpts.YAML) 161 }) 162 } 163 } 164 165 func TestViewRun(t *testing.T) { 166 aWorkflow := shared.Workflow{ 167 Name: "a workflow", 168 ID: 123, 169 Path: ".github/workflows/flow.yml", 170 State: shared.Active, 171 } 172 aWorkflowContent := `{"content":"bmFtZTogYSB3b3JrZmxvdwo="}` 173 aWorkflowInfo := heredoc.Doc(` 174 a workflow - flow.yml 175 ID: 123 176 177 Total runs 10 178 Recent runs 179 X cool commit a workflow trunk push 1 180 * cool commit a workflow trunk push 2 181 ✓ cool commit a workflow trunk push 3 182 X cool commit a workflow trunk push 4 183 184 To see more runs for this workflow, try: gh run list --workflow flow.yml 185 To see the YAML for this workflow, try: gh workflow view flow.yml --yaml 186 `) 187 188 tests := []struct { 189 name string 190 opts *ViewOptions 191 httpStubs func(*httpmock.Registry) 192 tty bool 193 wantOut string 194 wantErrOut string 195 wantErr bool 196 }{ 197 { 198 name: "no enabled workflows", 199 tty: true, 200 opts: &ViewOptions{ 201 Prompt: true, 202 }, 203 httpStubs: func(reg *httpmock.Registry) { 204 reg.Register( 205 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"), 206 httpmock.JSONResponse(shared.WorkflowsPayload{})) 207 }, 208 wantErrOut: "could not fetch workflows for OWNER/REPO: no workflows are enabled", 209 wantErr: true, 210 }, 211 { 212 name: "web", 213 tty: true, 214 opts: &ViewOptions{ 215 Selector: "123", 216 Web: true, 217 }, 218 httpStubs: func(reg *httpmock.Registry) { 219 reg.Register( 220 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 221 httpmock.JSONResponse(aWorkflow), 222 ) 223 }, 224 wantOut: "Opening github.com/OWNER/REPO/actions/workflows/flow.yml in your browser.\n", 225 }, 226 { 227 name: "web notty", 228 tty: false, 229 opts: &ViewOptions{ 230 Selector: "123", 231 Web: true, 232 }, 233 httpStubs: func(reg *httpmock.Registry) { 234 reg.Register( 235 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 236 httpmock.JSONResponse(aWorkflow), 237 ) 238 }, 239 wantOut: "", 240 }, 241 { 242 name: "web with yaml", 243 tty: true, 244 opts: &ViewOptions{ 245 Selector: "123", 246 YAML: true, 247 Web: true, 248 }, 249 httpStubs: func(reg *httpmock.Registry) { 250 reg.Register( 251 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 252 httpmock.JSONResponse(aWorkflow), 253 ) 254 reg.Register( 255 httpmock.GraphQL(`query RepositoryInfo\b`), 256 httpmock.StringResponse(`{ "data": { "repository": { "defaultBranchRef": { "name": "trunk" } } } }`), 257 ) 258 }, 259 wantOut: "Opening github.com/OWNER/REPO/blob/trunk/.github/workflows/flow.yml in your browser.\n", 260 }, 261 { 262 name: "web with yaml and ref", 263 tty: true, 264 opts: &ViewOptions{ 265 Selector: "123", 266 Ref: "base", 267 YAML: true, 268 Web: true, 269 }, 270 httpStubs: func(reg *httpmock.Registry) { 271 reg.Register( 272 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 273 httpmock.JSONResponse(aWorkflow), 274 ) 275 }, 276 wantOut: "Opening github.com/OWNER/REPO/blob/base/.github/workflows/flow.yml in your browser.\n", 277 }, 278 { 279 name: "workflow with yaml", 280 tty: true, 281 opts: &ViewOptions{ 282 Selector: "123", 283 YAML: true, 284 }, 285 httpStubs: func(reg *httpmock.Registry) { 286 reg.Register( 287 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 288 httpmock.JSONResponse(aWorkflow), 289 ) 290 reg.Register( 291 httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"), 292 httpmock.StringResponse(aWorkflowContent), 293 ) 294 }, 295 wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n", 296 }, 297 { 298 name: "workflow with yaml notty", 299 tty: false, 300 opts: &ViewOptions{ 301 Selector: "123", 302 YAML: true, 303 }, 304 httpStubs: func(reg *httpmock.Registry) { 305 reg.Register( 306 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 307 httpmock.JSONResponse(aWorkflow), 308 ) 309 reg.Register( 310 httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"), 311 httpmock.StringResponse(aWorkflowContent), 312 ) 313 }, 314 wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n", 315 }, 316 { 317 name: "workflow with yaml not found", 318 tty: true, 319 opts: &ViewOptions{ 320 Selector: "123", 321 YAML: true, 322 }, 323 httpStubs: func(reg *httpmock.Registry) { 324 reg.Register( 325 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 326 httpmock.JSONResponse(aWorkflow), 327 ) 328 reg.Register( 329 httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"), 330 httpmock.StatusStringResponse(404, "not Found"), 331 ) 332 }, 333 wantErr: true, 334 wantErrOut: "could not find workflow file flow.yml, try specifying a branch or tag using `--ref`", 335 }, 336 { 337 name: "workflow with yaml and ref", 338 tty: true, 339 opts: &ViewOptions{ 340 Selector: "123", 341 Ref: "456", 342 YAML: true, 343 }, 344 httpStubs: func(reg *httpmock.Registry) { 345 reg.Register( 346 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 347 httpmock.JSONResponse(aWorkflow), 348 ) 349 reg.Register( 350 httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"), 351 httpmock.StringResponse(aWorkflowContent), 352 ) 353 }, 354 wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n", 355 }, 356 { 357 name: "workflow info", 358 tty: true, 359 opts: &ViewOptions{ 360 Selector: "123", 361 }, 362 httpStubs: func(reg *httpmock.Registry) { 363 reg.Register( 364 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 365 httpmock.JSONResponse(aWorkflow), 366 ) 367 reg.Register( 368 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"), 369 httpmock.JSONResponse(runShared.RunsPayload{ 370 TotalCount: 10, 371 WorkflowRuns: runShared.TestRuns[0:4], 372 }), 373 ) 374 }, 375 wantOut: aWorkflowInfo, 376 }, 377 { 378 name: "workflow info notty", 379 tty: true, 380 opts: &ViewOptions{ 381 Selector: "123", 382 }, 383 httpStubs: func(reg *httpmock.Registry) { 384 reg.Register( 385 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), 386 httpmock.JSONResponse(aWorkflow), 387 ) 388 reg.Register( 389 httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"), 390 httpmock.JSONResponse(runShared.RunsPayload{ 391 TotalCount: 10, 392 WorkflowRuns: runShared.TestRuns[0:4], 393 }), 394 ) 395 }, 396 wantOut: aWorkflowInfo, 397 }, 398 } 399 400 for _, tt := range tests { 401 reg := &httpmock.Registry{} 402 tt.httpStubs(reg) 403 tt.opts.HttpClient = func() (*http.Client, error) { 404 return &http.Client{Transport: reg}, nil 405 } 406 407 ios, _, stdout, _ := iostreams.Test() 408 ios.SetStdoutTTY(tt.tty) 409 ios.SetStdinTTY(tt.tty) 410 tt.opts.IO = ios 411 412 tt.opts.BaseRepo = func() (ghrepo.Interface, error) { 413 return ghrepo.FromFullName("OWNER/REPO") 414 } 415 416 browser := &browser.Stub{} 417 tt.opts.Browser = browser 418 419 t.Run(tt.name, func(t *testing.T) { 420 err := runView(tt.opts) 421 if tt.wantErr { 422 assert.Error(t, err) 423 assert.Equal(t, tt.wantErrOut, err.Error()) 424 return 425 } 426 assert.NoError(t, err) 427 assert.Equal(t, tt.wantOut, stdout.String()) 428 reg.Verify(t) 429 }) 430 } 431 }