github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/repo/edit/edit_test.go (about)

     1  package edit
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"net/http"
     8  	"testing"
     9  
    10  	"github.com/ungtb10d/cli/v2/pkg/prompt"
    11  
    12  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    13  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    14  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    15  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    16  	"github.com/google/shlex"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestNewCmdEdit(t *testing.T) {
    22  	tests := []struct {
    23  		name     string
    24  		args     string
    25  		wantOpts EditOptions
    26  		wantErr  string
    27  	}{
    28  		{
    29  			name: "change repo description",
    30  			args: "--description hello",
    31  			wantOpts: EditOptions{
    32  				Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
    33  				Edits: EditRepositoryInput{
    34  					Description: sp("hello"),
    35  				},
    36  			},
    37  		},
    38  	}
    39  
    40  	for _, tt := range tests {
    41  		t.Run(tt.name, func(t *testing.T) {
    42  			ios, _, _, _ := iostreams.Test()
    43  			ios.SetStdoutTTY(true)
    44  			ios.SetStdinTTY(true)
    45  			ios.SetStderrTTY(true)
    46  
    47  			f := &cmdutil.Factory{
    48  				IOStreams: ios,
    49  				BaseRepo: func() (ghrepo.Interface, error) {
    50  					return ghrepo.New("OWNER", "REPO"), nil
    51  				},
    52  				HttpClient: func() (*http.Client, error) {
    53  					return nil, nil
    54  				},
    55  			}
    56  
    57  			argv, err := shlex.Split(tt.args)
    58  			assert.NoError(t, err)
    59  
    60  			var gotOpts *EditOptions
    61  			cmd := NewCmdEdit(f, func(opts *EditOptions) error {
    62  				gotOpts = opts
    63  				return nil
    64  			})
    65  			cmd.Flags().BoolP("help", "x", false, "")
    66  
    67  			cmd.SetArgs(argv)
    68  			cmd.SetIn(&bytes.Buffer{})
    69  			cmd.SetOut(io.Discard)
    70  			cmd.SetErr(io.Discard)
    71  
    72  			_, err = cmd.ExecuteC()
    73  			if tt.wantErr != "" {
    74  				assert.EqualError(t, err, tt.wantErr)
    75  				return
    76  			}
    77  			require.NoError(t, err)
    78  
    79  			assert.Equal(t, ghrepo.FullName(tt.wantOpts.Repository), ghrepo.FullName(gotOpts.Repository))
    80  			assert.Equal(t, tt.wantOpts.Edits, gotOpts.Edits)
    81  		})
    82  	}
    83  }
    84  
    85  func Test_editRun(t *testing.T) {
    86  	tests := []struct {
    87  		name        string
    88  		opts        EditOptions
    89  		httpStubs   func(*testing.T, *httpmock.Registry)
    90  		wantsStderr string
    91  		wantsErr    string
    92  	}{
    93  		{
    94  			name: "change name and description",
    95  			opts: EditOptions{
    96  				Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
    97  				Edits: EditRepositoryInput{
    98  					Homepage:    sp("newURL"),
    99  					Description: sp("hello world!"),
   100  				},
   101  			},
   102  			httpStubs: func(t *testing.T, r *httpmock.Registry) {
   103  				r.Register(
   104  					httpmock.REST("PATCH", "repos/OWNER/REPO"),
   105  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   106  						assert.Equal(t, 2, len(payload))
   107  						assert.Equal(t, "newURL", payload["homepage"])
   108  						assert.Equal(t, "hello world!", payload["description"])
   109  					}))
   110  			},
   111  		},
   112  		{
   113  			name: "add and remove topics",
   114  			opts: EditOptions{
   115  				Repository:   ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
   116  				AddTopics:    []string{"topic1", "topic2"},
   117  				RemoveTopics: []string{"topic3"},
   118  			},
   119  			httpStubs: func(t *testing.T, r *httpmock.Registry) {
   120  				r.Register(
   121  					httpmock.REST("GET", "repos/OWNER/REPO/topics"),
   122  					httpmock.StringResponse(`{"names":["topic2", "topic3", "go"]}`))
   123  				r.Register(
   124  					httpmock.REST("PUT", "repos/OWNER/REPO/topics"),
   125  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   126  						assert.Equal(t, 1, len(payload))
   127  						assert.Equal(t, []interface{}{"topic2", "go", "topic1"}, payload["names"])
   128  					}))
   129  			},
   130  		},
   131  	}
   132  
   133  	for _, tt := range tests {
   134  		t.Run(tt.name, func(t *testing.T) {
   135  			ios, _, _, _ := iostreams.Test()
   136  			ios.SetStdoutTTY(true)
   137  			ios.SetStdinTTY(true)
   138  			ios.SetStderrTTY(true)
   139  
   140  			httpReg := &httpmock.Registry{}
   141  			defer httpReg.Verify(t)
   142  			if tt.httpStubs != nil {
   143  				tt.httpStubs(t, httpReg)
   144  			}
   145  
   146  			opts := &tt.opts
   147  			opts.HTTPClient = &http.Client{Transport: httpReg}
   148  			opts.IO = ios
   149  			err := editRun(context.Background(), opts)
   150  			if tt.wantsErr == "" {
   151  				require.NoError(t, err)
   152  			} else {
   153  				assert.EqualError(t, err, tt.wantsErr)
   154  				return
   155  			}
   156  		})
   157  	}
   158  }
   159  
   160  func Test_editRun_interactive(t *testing.T) {
   161  	tests := []struct {
   162  		name        string
   163  		opts        EditOptions
   164  		askStubs    func(*prompt.AskStubber)
   165  		httpStubs   func(*testing.T, *httpmock.Registry)
   166  		wantsStderr string
   167  		wantsErr    string
   168  	}{
   169  		{
   170  			name: "updates repo description",
   171  			opts: EditOptions{
   172  				Repository:      ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
   173  				InteractiveMode: true,
   174  			},
   175  			askStubs: func(as *prompt.AskStubber) {
   176  				as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Description"})
   177  				as.StubPrompt("Description of the repository").AnswerWith("awesome repo description")
   178  			},
   179  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   180  				reg.Register(
   181  					httpmock.GraphQL(`query RepositoryInfo\b`),
   182  					httpmock.StringResponse(`
   183  					{
   184  						"data": {
   185  							"repository": {
   186  								"description": "old description",
   187  								"homePageUrl": "https://url.com",
   188  								"defaultBranchRef": {
   189  									"name": "main"
   190  								},
   191  								"isInOrganization": false,
   192  								"repositoryTopics": {
   193  									"nodes": [{
   194  										"topic": {
   195  											"name": "x"
   196  										}
   197  									}]
   198  								}
   199  							}
   200  						}
   201  					}`))
   202  				reg.Register(
   203  					httpmock.REST("PATCH", "repos/OWNER/REPO"),
   204  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   205  						assert.Equal(t, "awesome repo description", payload["description"])
   206  					}))
   207  			},
   208  		},
   209  		{
   210  			name: "updates repo topics",
   211  			opts: EditOptions{
   212  				Repository:      ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
   213  				InteractiveMode: true,
   214  			},
   215  			askStubs: func(as *prompt.AskStubber) {
   216  				as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Description", "Topics"})
   217  				as.StubPrompt("Description of the repository").AnswerWith("awesome repo description")
   218  				as.StubPrompt("Add topics?(csv format)").AnswerWith("a, b,c,d ")
   219  				as.StubPrompt("Remove Topics").AnswerWith([]string{"x"})
   220  			},
   221  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   222  				reg.Register(
   223  					httpmock.GraphQL(`query RepositoryInfo\b`),
   224  					httpmock.StringResponse(`
   225  					{
   226  						"data": {
   227  							"repository": {
   228  								"description": "old description",
   229  								"homePageUrl": "https://url.com",
   230  								"defaultBranchRef": {
   231  									"name": "main"
   232  								},
   233  								"isInOrganization": false,
   234  								"repositoryTopics": {
   235  									"nodes": [{
   236  										"topic": {
   237  											"name": "x"
   238  										}
   239  									}]
   240  								}
   241  							}
   242  						}
   243  					}`))
   244  				reg.Register(
   245  					httpmock.REST("PATCH", "repos/OWNER/REPO"),
   246  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   247  						assert.Equal(t, "awesome repo description", payload["description"])
   248  					}))
   249  				reg.Register(
   250  					httpmock.REST("PUT", "repos/OWNER/REPO/topics"),
   251  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   252  						assert.Equal(t, []interface{}{"a", "b", "c", "d"}, payload["names"])
   253  					}))
   254  			},
   255  		},
   256  		{
   257  			name: "updates repo merge options",
   258  			opts: EditOptions{
   259  				Repository:      ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
   260  				InteractiveMode: true,
   261  			},
   262  			askStubs: func(as *prompt.AskStubber) {
   263  				as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Merge Options"})
   264  				as.StubPrompt("Allowed merge strategies").AnswerWith([]string{allowMergeCommits, allowRebaseMerge})
   265  				as.StubPrompt("Enable Auto Merge?").AnswerWith(false)
   266  				as.StubPrompt("Automatically delete head branches after merging?").AnswerWith(false)
   267  			},
   268  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   269  				reg.Register(
   270  					httpmock.GraphQL(`query RepositoryInfo\b`),
   271  					httpmock.StringResponse(`
   272  					{
   273  						"data": {
   274  							"repository": {
   275  								"description": "old description",
   276  								"homePageUrl": "https://url.com",
   277  								"defaultBranchRef": {
   278  									"name": "main"
   279  								},
   280  								"isInOrganization": false,
   281  								"squashMergeAllowed": false,
   282  								"rebaseMergeAllowed": true,
   283  								"mergeCommitAllowed": true,
   284  								"deleteBranchOnMerge": false,
   285  								"repositoryTopics": {
   286  									"nodes": [{
   287  										"topic": {
   288  											"name": "x"
   289  										}
   290  									}]
   291  								}
   292  							}
   293  						}
   294  					}`))
   295  				reg.Register(
   296  					httpmock.REST("PATCH", "repos/OWNER/REPO"),
   297  					httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
   298  						assert.Equal(t, true, payload["allow_merge_commit"])
   299  						assert.Equal(t, false, payload["allow_squash_merge"])
   300  						assert.Equal(t, true, payload["allow_rebase_merge"])
   301  					}))
   302  			},
   303  		},
   304  	}
   305  
   306  	for _, tt := range tests {
   307  		t.Run(tt.name, func(t *testing.T) {
   308  			ios, _, _, _ := iostreams.Test()
   309  			ios.SetStdoutTTY(true)
   310  			ios.SetStdinTTY(true)
   311  			ios.SetStderrTTY(true)
   312  
   313  			httpReg := &httpmock.Registry{}
   314  			defer httpReg.Verify(t)
   315  			if tt.httpStubs != nil {
   316  				tt.httpStubs(t, httpReg)
   317  			}
   318  
   319  			opts := &tt.opts
   320  			opts.HTTPClient = &http.Client{Transport: httpReg}
   321  			opts.IO = ios
   322  			//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
   323  			as := prompt.NewAskStubber(t)
   324  			if tt.askStubs != nil {
   325  				tt.askStubs(as)
   326  			}
   327  
   328  			err := editRun(context.Background(), opts)
   329  			if tt.wantsErr == "" {
   330  				require.NoError(t, err)
   331  			} else {
   332  				assert.EqualError(t, err, tt.wantsErr)
   333  				return
   334  			}
   335  		})
   336  	}
   337  }
   338  
   339  func sp(v string) *string {
   340  	return &v
   341  }