github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/workflow/view/view_test.go (about)

     1  package view
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"testing"
     8  
     9  	"github.com/MakeNowJust/heredoc"
    10  	"github.com/cli/cli/internal/ghrepo"
    11  	runShared "github.com/cli/cli/pkg/cmd/run/shared"
    12  	"github.com/cli/cli/pkg/cmd/workflow/shared"
    13  	"github.com/cli/cli/pkg/cmdutil"
    14  	"github.com/cli/cli/pkg/httpmock"
    15  	"github.com/cli/cli/pkg/iostreams"
    16  	"github.com/cli/cli/pkg/prompt"
    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  			io, _, _, _ := iostreams.Test()
   128  			io.SetStdinTTY(tt.tty)
   129  			io.SetStdoutTTY(tt.tty)
   130  
   131  			f := &cmdutil.Factory{
   132  				IOStreams: io,
   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(ioutil.Discard)
   146  			cmd.SetErr(ioutil.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  timed out    trunk  push  1
   180  		-  cool commit  in progress  trunk  push  2
   181  		✓  cool commit  successful   trunk  push  3
   182  		✓  cool commit  cancelled    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  		askStubs   func(*prompt.AskStubber)
   193  		tty        bool
   194  		wantOut    string
   195  		wantErrOut string
   196  		wantErr    bool
   197  	}{
   198  		{
   199  			name: "no enabled workflows",
   200  			tty:  true,
   201  			opts: &ViewOptions{
   202  				Prompt: true,
   203  			},
   204  			httpStubs: func(reg *httpmock.Registry) {
   205  				reg.Register(
   206  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
   207  					httpmock.JSONResponse(shared.WorkflowsPayload{}))
   208  			},
   209  			wantErrOut: "could not fetch workflows for OWNER/REPO: no workflows are enabled",
   210  			wantErr:    true,
   211  		},
   212  		{
   213  			name: "web",
   214  			tty:  true,
   215  			opts: &ViewOptions{
   216  				Selector: "123",
   217  				Web:      true,
   218  			},
   219  			httpStubs: func(reg *httpmock.Registry) {
   220  				reg.Register(
   221  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   222  					httpmock.JSONResponse(aWorkflow),
   223  				)
   224  			},
   225  			wantOut: "Opening github.com/OWNER/REPO/actions/workflows/flow.yml in your browser.\n",
   226  		},
   227  		{
   228  			name: "web notty",
   229  			tty:  false,
   230  			opts: &ViewOptions{
   231  				Selector: "123",
   232  				Web:      true,
   233  			},
   234  			httpStubs: func(reg *httpmock.Registry) {
   235  				reg.Register(
   236  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   237  					httpmock.JSONResponse(aWorkflow),
   238  				)
   239  			},
   240  			wantOut: "",
   241  		},
   242  		{
   243  			name: "web with yaml",
   244  			tty:  true,
   245  			opts: &ViewOptions{
   246  				Selector: "123",
   247  				YAML:     true,
   248  				Web:      true,
   249  			},
   250  			httpStubs: func(reg *httpmock.Registry) {
   251  				reg.Register(
   252  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   253  					httpmock.JSONResponse(aWorkflow),
   254  				)
   255  				reg.Register(
   256  					httpmock.GraphQL(`query RepositoryInfo\b`),
   257  					httpmock.StringResponse(`{ "data": { "repository": { "defaultBranchRef": { "name": "trunk" } } } }`),
   258  				)
   259  			},
   260  			wantOut: "Opening github.com/OWNER/REPO/blob/trunk/.github/workflows/flow.yml in your browser.\n",
   261  		},
   262  		{
   263  			name: "web with yaml and ref",
   264  			tty:  true,
   265  			opts: &ViewOptions{
   266  				Selector: "123",
   267  				Ref:      "base",
   268  				YAML:     true,
   269  				Web:      true,
   270  			},
   271  			httpStubs: func(reg *httpmock.Registry) {
   272  				reg.Register(
   273  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   274  					httpmock.JSONResponse(aWorkflow),
   275  				)
   276  			},
   277  			wantOut: "Opening github.com/OWNER/REPO/blob/base/.github/workflows/flow.yml in your browser.\n",
   278  		},
   279  		{
   280  			name: "workflow with yaml",
   281  			tty:  true,
   282  			opts: &ViewOptions{
   283  				Selector: "123",
   284  				YAML:     true,
   285  			},
   286  			httpStubs: func(reg *httpmock.Registry) {
   287  				reg.Register(
   288  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   289  					httpmock.JSONResponse(aWorkflow),
   290  				)
   291  				reg.Register(
   292  					httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
   293  					httpmock.StringResponse(aWorkflowContent),
   294  				)
   295  			},
   296  			wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
   297  		},
   298  		{
   299  			name: "workflow with yaml notty",
   300  			tty:  false,
   301  			opts: &ViewOptions{
   302  				Selector: "123",
   303  				YAML:     true,
   304  			},
   305  			httpStubs: func(reg *httpmock.Registry) {
   306  				reg.Register(
   307  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   308  					httpmock.JSONResponse(aWorkflow),
   309  				)
   310  				reg.Register(
   311  					httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
   312  					httpmock.StringResponse(aWorkflowContent),
   313  				)
   314  			},
   315  			wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
   316  		},
   317  		{
   318  			name: "workflow with yaml not found",
   319  			tty:  true,
   320  			opts: &ViewOptions{
   321  				Selector: "123",
   322  				YAML:     true,
   323  			},
   324  			httpStubs: func(reg *httpmock.Registry) {
   325  				reg.Register(
   326  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   327  					httpmock.JSONResponse(aWorkflow),
   328  				)
   329  				reg.Register(
   330  					httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
   331  					httpmock.StatusStringResponse(404, "not Found"),
   332  				)
   333  			},
   334  			wantErr:    true,
   335  			wantErrOut: "could not find workflow file flow.yml, try specifying a branch or tag using `--ref`",
   336  		},
   337  		{
   338  			name: "workflow with yaml and ref",
   339  			tty:  true,
   340  			opts: &ViewOptions{
   341  				Selector: "123",
   342  				Ref:      "456",
   343  				YAML:     true,
   344  			},
   345  			httpStubs: func(reg *httpmock.Registry) {
   346  				reg.Register(
   347  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   348  					httpmock.JSONResponse(aWorkflow),
   349  				)
   350  				reg.Register(
   351  					httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
   352  					httpmock.StringResponse(aWorkflowContent),
   353  				)
   354  			},
   355  			wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
   356  		},
   357  		{
   358  			name: "workflow info",
   359  			tty:  true,
   360  			opts: &ViewOptions{
   361  				Selector: "123",
   362  			},
   363  			httpStubs: func(reg *httpmock.Registry) {
   364  				reg.Register(
   365  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   366  					httpmock.JSONResponse(aWorkflow),
   367  				)
   368  				reg.Register(
   369  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"),
   370  					httpmock.JSONResponse(runShared.RunsPayload{
   371  						TotalCount:   10,
   372  						WorkflowRuns: runShared.TestRuns[0:4],
   373  					}),
   374  				)
   375  			},
   376  			wantOut: aWorkflowInfo,
   377  		},
   378  		{
   379  			name: "workflow info notty",
   380  			tty:  true,
   381  			opts: &ViewOptions{
   382  				Selector: "123",
   383  			},
   384  			httpStubs: func(reg *httpmock.Registry) {
   385  				reg.Register(
   386  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   387  					httpmock.JSONResponse(aWorkflow),
   388  				)
   389  				reg.Register(
   390  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"),
   391  					httpmock.JSONResponse(runShared.RunsPayload{
   392  						TotalCount:   10,
   393  						WorkflowRuns: runShared.TestRuns[0:4],
   394  					}),
   395  				)
   396  			},
   397  			wantOut: aWorkflowInfo,
   398  		},
   399  	}
   400  
   401  	for _, tt := range tests {
   402  		reg := &httpmock.Registry{}
   403  		tt.httpStubs(reg)
   404  		tt.opts.HttpClient = func() (*http.Client, error) {
   405  			return &http.Client{Transport: reg}, nil
   406  		}
   407  
   408  		io, _, stdout, _ := iostreams.Test()
   409  		io.SetStdoutTTY(tt.tty)
   410  		io.SetStdinTTY(tt.tty)
   411  		tt.opts.IO = io
   412  
   413  		tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
   414  			return ghrepo.FromFullName("OWNER/REPO")
   415  		}
   416  
   417  		browser := &cmdutil.TestBrowser{}
   418  		tt.opts.Browser = browser
   419  
   420  		as, teardown := prompt.InitAskStubber()
   421  		defer teardown()
   422  		if tt.askStubs != nil {
   423  			tt.askStubs(as)
   424  		}
   425  
   426  		t.Run(tt.name, func(t *testing.T) {
   427  			err := runView(tt.opts)
   428  			if tt.wantErr {
   429  				assert.Error(t, err)
   430  				assert.Equal(t, tt.wantErrOut, err.Error())
   431  				return
   432  			}
   433  			assert.NoError(t, err)
   434  			assert.Equal(t, tt.wantOut, stdout.String())
   435  			reg.Verify(t)
   436  		})
   437  	}
   438  }