github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/pr/shared/finder_test.go (about)

     1  package shared
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"net/url"
     7  	"testing"
     8  
     9  	"github.com/ungtb10d/cli/v2/context"
    10  	"github.com/ungtb10d/cli/v2/git"
    11  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    12  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    13  )
    14  
    15  func TestFind(t *testing.T) {
    16  	type args struct {
    17  		baseRepoFn   func() (ghrepo.Interface, error)
    18  		branchFn     func() (string, error)
    19  		branchConfig func(string) git.BranchConfig
    20  		remotesFn    func() (context.Remotes, error)
    21  		selector     string
    22  		fields       []string
    23  		baseBranch   string
    24  	}
    25  	tests := []struct {
    26  		name     string
    27  		args     args
    28  		httpStub func(*httpmock.Registry)
    29  		wantPR   int
    30  		wantRepo string
    31  		wantErr  bool
    32  	}{
    33  		{
    34  			name: "number argument",
    35  			args: args{
    36  				selector: "13",
    37  				fields:   []string{"id", "number"},
    38  				baseRepoFn: func() (ghrepo.Interface, error) {
    39  					return ghrepo.FromFullName("OWNER/REPO")
    40  				},
    41  			},
    42  			httpStub: func(r *httpmock.Registry) {
    43  				r.Register(
    44  					httpmock.GraphQL(`query PullRequestByNumber\b`),
    45  					httpmock.StringResponse(`{"data":{"repository":{
    46  						"pullRequest":{"number":13}
    47  					}}}`))
    48  			},
    49  			wantPR:   13,
    50  			wantRepo: "https://github.com/OWNER/REPO",
    51  		},
    52  		{
    53  			name: "number argument with base branch",
    54  			args: args{
    55  				selector:   "13",
    56  				baseBranch: "main",
    57  				fields:     []string{"id", "number"},
    58  				baseRepoFn: func() (ghrepo.Interface, error) {
    59  					return ghrepo.FromFullName("OWNER/REPO")
    60  				},
    61  			},
    62  			httpStub: func(r *httpmock.Registry) {
    63  				r.Register(
    64  					httpmock.GraphQL(`query PullRequestForBranch\b`),
    65  					httpmock.StringResponse(`{"data":{"repository":{
    66  						"pullRequests":{"nodes":[
    67  							{
    68  								"number": 123,
    69  								"state": "OPEN",
    70  								"baseRefName": "main",
    71  								"headRefName": "13",
    72  								"isCrossRepository": false,
    73  								"headRepositoryOwner": {"login":"OWNER"}
    74  							}
    75  						]}
    76  					}}}`))
    77  			},
    78  			wantPR:   123,
    79  			wantRepo: "https://github.com/OWNER/REPO",
    80  		},
    81  		{
    82  			name: "baseRepo is error",
    83  			args: args{
    84  				selector: "13",
    85  				fields:   []string{"id", "number"},
    86  				baseRepoFn: func() (ghrepo.Interface, error) {
    87  					return nil, errors.New("baseRepoErr")
    88  				},
    89  			},
    90  			wantErr: true,
    91  		},
    92  		{
    93  			name: "blank fields is error",
    94  			args: args{
    95  				selector: "13",
    96  				fields:   []string{},
    97  			},
    98  			wantErr: true,
    99  		},
   100  		{
   101  			name: "number only",
   102  			args: args{
   103  				selector: "13",
   104  				fields:   []string{"number"},
   105  				baseRepoFn: func() (ghrepo.Interface, error) {
   106  					return ghrepo.FromFullName("OWNER/REPO")
   107  				},
   108  			},
   109  			httpStub: nil,
   110  			wantPR:   13,
   111  			wantRepo: "https://github.com/OWNER/REPO",
   112  		},
   113  		{
   114  			name: "number with hash argument",
   115  			args: args{
   116  				selector: "#13",
   117  				fields:   []string{"id", "number"},
   118  				baseRepoFn: func() (ghrepo.Interface, error) {
   119  					return ghrepo.FromFullName("OWNER/REPO")
   120  				},
   121  			},
   122  			httpStub: func(r *httpmock.Registry) {
   123  				r.Register(
   124  					httpmock.GraphQL(`query PullRequestByNumber\b`),
   125  					httpmock.StringResponse(`{"data":{"repository":{
   126  						"pullRequest":{"number":13}
   127  					}}}`))
   128  			},
   129  			wantPR:   13,
   130  			wantRepo: "https://github.com/OWNER/REPO",
   131  		},
   132  		{
   133  			name: "URL argument",
   134  			args: args{
   135  				selector:   "https://example.org/OWNER/REPO/pull/13/files",
   136  				fields:     []string{"id", "number"},
   137  				baseRepoFn: nil,
   138  			},
   139  			httpStub: func(r *httpmock.Registry) {
   140  				r.Register(
   141  					httpmock.GraphQL(`query PullRequestByNumber\b`),
   142  					httpmock.StringResponse(`{"data":{"repository":{
   143  						"pullRequest":{"number":13}
   144  					}}}`))
   145  			},
   146  			wantPR:   13,
   147  			wantRepo: "https://example.org/OWNER/REPO",
   148  		},
   149  		{
   150  			name: "branch argument",
   151  			args: args{
   152  				selector: "blueberries",
   153  				fields:   []string{"id", "number"},
   154  				baseRepoFn: func() (ghrepo.Interface, error) {
   155  					return ghrepo.FromFullName("OWNER/REPO")
   156  				},
   157  			},
   158  			httpStub: func(r *httpmock.Registry) {
   159  				r.Register(
   160  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   161  					httpmock.StringResponse(`{"data":{"repository":{
   162  						"pullRequests":{"nodes":[
   163  							{
   164  								"number": 14,
   165  								"state": "CLOSED",
   166  								"baseRefName": "main",
   167  								"headRefName": "blueberries",
   168  								"isCrossRepository": false,
   169  								"headRepositoryOwner": {"login":"OWNER"}
   170  							},
   171  							{
   172  								"number": 13,
   173  								"state": "OPEN",
   174  								"baseRefName": "main",
   175  								"headRefName": "blueberries",
   176  								"isCrossRepository": false,
   177  								"headRepositoryOwner": {"login":"OWNER"}
   178  							}
   179  						]}
   180  					}}}`))
   181  			},
   182  			wantPR:   13,
   183  			wantRepo: "https://github.com/OWNER/REPO",
   184  		},
   185  		{
   186  			name: "branch argument with base branch",
   187  			args: args{
   188  				selector:   "blueberries",
   189  				baseBranch: "main",
   190  				fields:     []string{"id", "number"},
   191  				baseRepoFn: func() (ghrepo.Interface, error) {
   192  					return ghrepo.FromFullName("OWNER/REPO")
   193  				},
   194  			},
   195  			httpStub: func(r *httpmock.Registry) {
   196  				r.Register(
   197  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   198  					httpmock.StringResponse(`{"data":{"repository":{
   199  						"pullRequests":{"nodes":[
   200  							{
   201  								"number": 14,
   202  								"state": "OPEN",
   203  								"baseRefName": "dev",
   204  								"headRefName": "blueberries",
   205  								"isCrossRepository": false,
   206  								"headRepositoryOwner": {"login":"OWNER"}
   207  							},
   208  							{
   209  								"number": 13,
   210  								"state": "OPEN",
   211  								"baseRefName": "main",
   212  								"headRefName": "blueberries",
   213  								"isCrossRepository": false,
   214  								"headRepositoryOwner": {"login":"OWNER"}
   215  							}
   216  						]}
   217  					}}}`))
   218  			},
   219  			wantPR:   13,
   220  			wantRepo: "https://github.com/OWNER/REPO",
   221  		},
   222  		{
   223  			name: "no argument reads current branch",
   224  			args: args{
   225  				selector: "",
   226  				fields:   []string{"id", "number"},
   227  				baseRepoFn: func() (ghrepo.Interface, error) {
   228  					return ghrepo.FromFullName("OWNER/REPO")
   229  				},
   230  				branchFn: func() (string, error) {
   231  					return "blueberries", nil
   232  				},
   233  				branchConfig: func(branch string) (c git.BranchConfig) {
   234  					return
   235  				},
   236  			},
   237  			httpStub: func(r *httpmock.Registry) {
   238  				r.Register(
   239  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   240  					httpmock.StringResponse(`{"data":{"repository":{
   241  						"pullRequests":{"nodes":[
   242  							{
   243  								"number": 13,
   244  								"state": "OPEN",
   245  								"baseRefName": "main",
   246  								"headRefName": "blueberries",
   247  								"isCrossRepository": false,
   248  								"headRepositoryOwner": {"login":"OWNER"}
   249  							}
   250  						]}
   251  					}}}`))
   252  			},
   253  			wantPR:   13,
   254  			wantRepo: "https://github.com/OWNER/REPO",
   255  		},
   256  		{
   257  			name: "current branch with merged pr",
   258  			args: args{
   259  				selector: "",
   260  				fields:   []string{"id", "number"},
   261  				baseRepoFn: func() (ghrepo.Interface, error) {
   262  					return ghrepo.FromFullName("OWNER/REPO")
   263  				},
   264  				branchFn: func() (string, error) {
   265  					return "blueberries", nil
   266  				},
   267  				branchConfig: func(branch string) (c git.BranchConfig) {
   268  					return
   269  				},
   270  			},
   271  			httpStub: func(r *httpmock.Registry) {
   272  				r.Register(
   273  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   274  					httpmock.StringResponse(`{"data":{"repository":{
   275  						"pullRequests":{"nodes":[
   276  							{
   277  								"number": 13,
   278  								"state": "MERGED",
   279  								"baseRefName": "main",
   280  								"headRefName": "blueberries",
   281  								"isCrossRepository": false,
   282  								"headRepositoryOwner": {"login":"OWNER"}
   283  							}
   284  						]},
   285  						"defaultBranchRef":{
   286  							"name": "blueberries"
   287  						}
   288  					}}}`))
   289  			},
   290  			wantErr: true,
   291  		},
   292  		{
   293  			name: "current branch is error",
   294  			args: args{
   295  				selector: "",
   296  				fields:   []string{"id", "number"},
   297  				baseRepoFn: func() (ghrepo.Interface, error) {
   298  					return ghrepo.FromFullName("OWNER/REPO")
   299  				},
   300  				branchFn: func() (string, error) {
   301  					return "", errors.New("branchErr")
   302  				},
   303  			},
   304  			wantErr: true,
   305  		},
   306  		{
   307  			name: "current branch with upstream configuration",
   308  			args: args{
   309  				selector: "",
   310  				fields:   []string{"id", "number"},
   311  				baseRepoFn: func() (ghrepo.Interface, error) {
   312  					return ghrepo.FromFullName("OWNER/REPO")
   313  				},
   314  				branchFn: func() (string, error) {
   315  					return "blueberries", nil
   316  				},
   317  				branchConfig: func(branch string) (c git.BranchConfig) {
   318  					c.MergeRef = "refs/heads/blue-upstream-berries"
   319  					c.RemoteName = "origin"
   320  					return
   321  				},
   322  				remotesFn: func() (context.Remotes, error) {
   323  					return context.Remotes{{
   324  						Remote: &git.Remote{Name: "origin"},
   325  						Repo:   ghrepo.New("UPSTREAMOWNER", "REPO"),
   326  					}}, nil
   327  				},
   328  			},
   329  			httpStub: func(r *httpmock.Registry) {
   330  				r.Register(
   331  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   332  					httpmock.StringResponse(`{"data":{"repository":{
   333  						"pullRequests":{"nodes":[
   334  							{
   335  								"number": 13,
   336  								"state": "OPEN",
   337  								"baseRefName": "main",
   338  								"headRefName": "blue-upstream-berries",
   339  								"isCrossRepository": true,
   340  								"headRepositoryOwner": {"login":"UPSTREAMOWNER"}
   341  							}
   342  						]}
   343  					}}}`))
   344  			},
   345  			wantPR:   13,
   346  			wantRepo: "https://github.com/OWNER/REPO",
   347  		},
   348  		{
   349  			name: "current branch with upstream configuration",
   350  			args: args{
   351  				selector: "",
   352  				fields:   []string{"id", "number"},
   353  				baseRepoFn: func() (ghrepo.Interface, error) {
   354  					return ghrepo.FromFullName("OWNER/REPO")
   355  				},
   356  				branchFn: func() (string, error) {
   357  					return "blueberries", nil
   358  				},
   359  				branchConfig: func(branch string) (c git.BranchConfig) {
   360  					u, _ := url.Parse("https://github.com/UPSTREAMOWNER/REPO")
   361  					c.MergeRef = "refs/heads/blue-upstream-berries"
   362  					c.RemoteURL = u
   363  					return
   364  				},
   365  				remotesFn: nil,
   366  			},
   367  			httpStub: func(r *httpmock.Registry) {
   368  				r.Register(
   369  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   370  					httpmock.StringResponse(`{"data":{"repository":{
   371  						"pullRequests":{"nodes":[
   372  							{
   373  								"number": 13,
   374  								"state": "OPEN",
   375  								"baseRefName": "main",
   376  								"headRefName": "blue-upstream-berries",
   377  								"isCrossRepository": true,
   378  								"headRepositoryOwner": {"login":"UPSTREAMOWNER"}
   379  							}
   380  						]}
   381  					}}}`))
   382  			},
   383  			wantPR:   13,
   384  			wantRepo: "https://github.com/OWNER/REPO",
   385  		},
   386  		{
   387  			name: "current branch made by pr checkout",
   388  			args: args{
   389  				selector: "",
   390  				fields:   []string{"id", "number"},
   391  				baseRepoFn: func() (ghrepo.Interface, error) {
   392  					return ghrepo.FromFullName("OWNER/REPO")
   393  				},
   394  				branchFn: func() (string, error) {
   395  					return "blueberries", nil
   396  				},
   397  				branchConfig: func(branch string) (c git.BranchConfig) {
   398  					c.MergeRef = "refs/pull/13/head"
   399  					return
   400  				},
   401  			},
   402  			httpStub: func(r *httpmock.Registry) {
   403  				r.Register(
   404  					httpmock.GraphQL(`query PullRequestByNumber\b`),
   405  					httpmock.StringResponse(`{"data":{"repository":{
   406  						"pullRequest":{"number":13}
   407  					}}}`))
   408  			},
   409  			wantPR:   13,
   410  			wantRepo: "https://github.com/OWNER/REPO",
   411  		},
   412  	}
   413  	for _, tt := range tests {
   414  		t.Run(tt.name, func(t *testing.T) {
   415  			reg := &httpmock.Registry{}
   416  			defer reg.Verify(t)
   417  			if tt.httpStub != nil {
   418  				tt.httpStub(reg)
   419  			}
   420  
   421  			f := finder{
   422  				httpClient: func() (*http.Client, error) {
   423  					return &http.Client{Transport: reg}, nil
   424  				},
   425  				baseRepoFn:   tt.args.baseRepoFn,
   426  				branchFn:     tt.args.branchFn,
   427  				branchConfig: tt.args.branchConfig,
   428  				remotesFn:    tt.args.remotesFn,
   429  			}
   430  
   431  			pr, repo, err := f.Find(FindOptions{
   432  				Selector:   tt.args.selector,
   433  				Fields:     tt.args.fields,
   434  				BaseBranch: tt.args.baseBranch,
   435  			})
   436  			if (err != nil) != tt.wantErr {
   437  				t.Errorf("Find() error = %v, wantErr %v", err, tt.wantErr)
   438  				return
   439  			}
   440  			if tt.wantErr {
   441  				if tt.wantPR > 0 {
   442  					t.Error("wantPR field is not checked in error case")
   443  				}
   444  				if tt.wantRepo != "" {
   445  					t.Error("wantRepo field is not checked in error case")
   446  				}
   447  				return
   448  			}
   449  
   450  			if pr.Number != tt.wantPR {
   451  				t.Errorf("want pr #%d, got #%d", tt.wantPR, pr.Number)
   452  			}
   453  			repoURL := ghrepo.GenerateRepoURL(repo, "")
   454  			if repoURL != tt.wantRepo {
   455  				t.Errorf("want repo %s, got %s", tt.wantRepo, repoURL)
   456  			}
   457  		})
   458  	}
   459  }