github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/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/andrewhsu/cli/v2/context"
    10  	"github.com/andrewhsu/cli/v2/git"
    11  	"github.com/andrewhsu/cli/v2/internal/ghrepo"
    12  	"github.com/andrewhsu/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: "baseRepo is error",
    54  			args: args{
    55  				selector: "13",
    56  				fields:   []string{"id", "number"},
    57  				baseRepoFn: func() (ghrepo.Interface, error) {
    58  					return nil, errors.New("baseRepoErr")
    59  				},
    60  			},
    61  			wantErr: true,
    62  		},
    63  		{
    64  			name: "blank fields is error",
    65  			args: args{
    66  				selector: "13",
    67  				fields:   []string{},
    68  			},
    69  			wantErr: true,
    70  		},
    71  		{
    72  			name: "number only",
    73  			args: args{
    74  				selector: "13",
    75  				fields:   []string{"number"},
    76  				baseRepoFn: func() (ghrepo.Interface, error) {
    77  					return ghrepo.FromFullName("OWNER/REPO")
    78  				},
    79  			},
    80  			httpStub: nil,
    81  			wantPR:   13,
    82  			wantRepo: "https://github.com/OWNER/REPO",
    83  		},
    84  		{
    85  			name: "number with hash argument",
    86  			args: args{
    87  				selector: "#13",
    88  				fields:   []string{"id", "number"},
    89  				baseRepoFn: func() (ghrepo.Interface, error) {
    90  					return ghrepo.FromFullName("OWNER/REPO")
    91  				},
    92  			},
    93  			httpStub: func(r *httpmock.Registry) {
    94  				r.Register(
    95  					httpmock.GraphQL(`query PullRequestByNumber\b`),
    96  					httpmock.StringResponse(`{"data":{"repository":{
    97  						"pullRequest":{"number":13}
    98  					}}}`))
    99  			},
   100  			wantPR:   13,
   101  			wantRepo: "https://github.com/OWNER/REPO",
   102  		},
   103  		{
   104  			name: "URL argument",
   105  			args: args{
   106  				selector:   "https://example.org/OWNER/REPO/pull/13/files",
   107  				fields:     []string{"id", "number"},
   108  				baseRepoFn: nil,
   109  			},
   110  			httpStub: func(r *httpmock.Registry) {
   111  				r.Register(
   112  					httpmock.GraphQL(`query PullRequestByNumber\b`),
   113  					httpmock.StringResponse(`{"data":{"repository":{
   114  						"pullRequest":{"number":13}
   115  					}}}`))
   116  			},
   117  			wantPR:   13,
   118  			wantRepo: "https://example.org/OWNER/REPO",
   119  		},
   120  		{
   121  			name: "branch argument",
   122  			args: args{
   123  				selector: "blueberries",
   124  				fields:   []string{"id", "number"},
   125  				baseRepoFn: func() (ghrepo.Interface, error) {
   126  					return ghrepo.FromFullName("OWNER/REPO")
   127  				},
   128  			},
   129  			httpStub: func(r *httpmock.Registry) {
   130  				r.Register(
   131  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   132  					httpmock.StringResponse(`{"data":{"repository":{
   133  						"pullRequests":{"nodes":[
   134  							{
   135  								"number": 14,
   136  								"state": "CLOSED",
   137  								"baseRefName": "main",
   138  								"headRefName": "blueberries",
   139  								"isCrossRepository": false,
   140  								"headRepositoryOwner": {"login":"OWNER"}
   141  							},
   142  							{
   143  								"number": 13,
   144  								"state": "OPEN",
   145  								"baseRefName": "main",
   146  								"headRefName": "blueberries",
   147  								"isCrossRepository": false,
   148  								"headRepositoryOwner": {"login":"OWNER"}
   149  							}
   150  						]}
   151  					}}}`))
   152  			},
   153  			wantPR:   13,
   154  			wantRepo: "https://github.com/OWNER/REPO",
   155  		},
   156  		{
   157  			name: "branch argument with base branch",
   158  			args: args{
   159  				selector:   "blueberries",
   160  				baseBranch: "main",
   161  				fields:     []string{"id", "number"},
   162  				baseRepoFn: func() (ghrepo.Interface, error) {
   163  					return ghrepo.FromFullName("OWNER/REPO")
   164  				},
   165  			},
   166  			httpStub: func(r *httpmock.Registry) {
   167  				r.Register(
   168  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   169  					httpmock.StringResponse(`{"data":{"repository":{
   170  						"pullRequests":{"nodes":[
   171  							{
   172  								"number": 14,
   173  								"state": "OPEN",
   174  								"baseRefName": "dev",
   175  								"headRefName": "blueberries",
   176  								"isCrossRepository": false,
   177  								"headRepositoryOwner": {"login":"OWNER"}
   178  							},
   179  							{
   180  								"number": 13,
   181  								"state": "OPEN",
   182  								"baseRefName": "main",
   183  								"headRefName": "blueberries",
   184  								"isCrossRepository": false,
   185  								"headRepositoryOwner": {"login":"OWNER"}
   186  							}
   187  						]}
   188  					}}}`))
   189  			},
   190  			wantPR:   13,
   191  			wantRepo: "https://github.com/OWNER/REPO",
   192  		},
   193  		{
   194  			name: "no argument reads current branch",
   195  			args: args{
   196  				selector: "",
   197  				fields:   []string{"id", "number"},
   198  				baseRepoFn: func() (ghrepo.Interface, error) {
   199  					return ghrepo.FromFullName("OWNER/REPO")
   200  				},
   201  				branchFn: func() (string, error) {
   202  					return "blueberries", nil
   203  				},
   204  				branchConfig: func(branch string) (c git.BranchConfig) {
   205  					return
   206  				},
   207  			},
   208  			httpStub: func(r *httpmock.Registry) {
   209  				r.Register(
   210  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   211  					httpmock.StringResponse(`{"data":{"repository":{
   212  						"pullRequests":{"nodes":[
   213  							{
   214  								"number": 13,
   215  								"state": "OPEN",
   216  								"baseRefName": "main",
   217  								"headRefName": "blueberries",
   218  								"isCrossRepository": false,
   219  								"headRepositoryOwner": {"login":"OWNER"}
   220  							}
   221  						]}
   222  					}}}`))
   223  			},
   224  			wantPR:   13,
   225  			wantRepo: "https://github.com/OWNER/REPO",
   226  		},
   227  		{
   228  			name: "current branch is error",
   229  			args: args{
   230  				selector: "",
   231  				fields:   []string{"id", "number"},
   232  				baseRepoFn: func() (ghrepo.Interface, error) {
   233  					return ghrepo.FromFullName("OWNER/REPO")
   234  				},
   235  				branchFn: func() (string, error) {
   236  					return "", errors.New("branchErr")
   237  				},
   238  			},
   239  			wantErr: true,
   240  		},
   241  		{
   242  			name: "current branch with upstream configuration",
   243  			args: args{
   244  				selector: "",
   245  				fields:   []string{"id", "number"},
   246  				baseRepoFn: func() (ghrepo.Interface, error) {
   247  					return ghrepo.FromFullName("OWNER/REPO")
   248  				},
   249  				branchFn: func() (string, error) {
   250  					return "blueberries", nil
   251  				},
   252  				branchConfig: func(branch string) (c git.BranchConfig) {
   253  					c.MergeRef = "refs/heads/blue-upstream-berries"
   254  					c.RemoteName = "origin"
   255  					return
   256  				},
   257  				remotesFn: func() (context.Remotes, error) {
   258  					return context.Remotes{{
   259  						Remote: &git.Remote{Name: "origin"},
   260  						Repo:   ghrepo.New("UPSTREAMOWNER", "REPO"),
   261  					}}, nil
   262  				},
   263  			},
   264  			httpStub: func(r *httpmock.Registry) {
   265  				r.Register(
   266  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   267  					httpmock.StringResponse(`{"data":{"repository":{
   268  						"pullRequests":{"nodes":[
   269  							{
   270  								"number": 13,
   271  								"state": "OPEN",
   272  								"baseRefName": "main",
   273  								"headRefName": "blue-upstream-berries",
   274  								"isCrossRepository": true,
   275  								"headRepositoryOwner": {"login":"UPSTREAMOWNER"}
   276  							}
   277  						]}
   278  					}}}`))
   279  			},
   280  			wantPR:   13,
   281  			wantRepo: "https://github.com/OWNER/REPO",
   282  		},
   283  		{
   284  			name: "current branch with upstream configuration",
   285  			args: args{
   286  				selector: "",
   287  				fields:   []string{"id", "number"},
   288  				baseRepoFn: func() (ghrepo.Interface, error) {
   289  					return ghrepo.FromFullName("OWNER/REPO")
   290  				},
   291  				branchFn: func() (string, error) {
   292  					return "blueberries", nil
   293  				},
   294  				branchConfig: func(branch string) (c git.BranchConfig) {
   295  					u, _ := url.Parse("https://github.com/UPSTREAMOWNER/REPO")
   296  					c.MergeRef = "refs/heads/blue-upstream-berries"
   297  					c.RemoteURL = u
   298  					return
   299  				},
   300  				remotesFn: nil,
   301  			},
   302  			httpStub: func(r *httpmock.Registry) {
   303  				r.Register(
   304  					httpmock.GraphQL(`query PullRequestForBranch\b`),
   305  					httpmock.StringResponse(`{"data":{"repository":{
   306  						"pullRequests":{"nodes":[
   307  							{
   308  								"number": 13,
   309  								"state": "OPEN",
   310  								"baseRefName": "main",
   311  								"headRefName": "blue-upstream-berries",
   312  								"isCrossRepository": true,
   313  								"headRepositoryOwner": {"login":"UPSTREAMOWNER"}
   314  							}
   315  						]}
   316  					}}}`))
   317  			},
   318  			wantPR:   13,
   319  			wantRepo: "https://github.com/OWNER/REPO",
   320  		},
   321  		{
   322  			name: "current branch made by pr checkout",
   323  			args: args{
   324  				selector: "",
   325  				fields:   []string{"id", "number"},
   326  				baseRepoFn: func() (ghrepo.Interface, error) {
   327  					return ghrepo.FromFullName("OWNER/REPO")
   328  				},
   329  				branchFn: func() (string, error) {
   330  					return "blueberries", nil
   331  				},
   332  				branchConfig: func(branch string) (c git.BranchConfig) {
   333  					c.MergeRef = "refs/pull/13/head"
   334  					return
   335  				},
   336  			},
   337  			httpStub: func(r *httpmock.Registry) {
   338  				r.Register(
   339  					httpmock.GraphQL(`query PullRequestByNumber\b`),
   340  					httpmock.StringResponse(`{"data":{"repository":{
   341  						"pullRequest":{"number":13}
   342  					}}}`))
   343  			},
   344  			wantPR:   13,
   345  			wantRepo: "https://github.com/OWNER/REPO",
   346  		},
   347  	}
   348  	for _, tt := range tests {
   349  		t.Run(tt.name, func(t *testing.T) {
   350  			reg := &httpmock.Registry{}
   351  			defer reg.Verify(t)
   352  			if tt.httpStub != nil {
   353  				tt.httpStub(reg)
   354  			}
   355  
   356  			f := finder{
   357  				httpClient: func() (*http.Client, error) {
   358  					return &http.Client{Transport: reg}, nil
   359  				},
   360  				baseRepoFn:   tt.args.baseRepoFn,
   361  				branchFn:     tt.args.branchFn,
   362  				branchConfig: tt.args.branchConfig,
   363  				remotesFn:    tt.args.remotesFn,
   364  			}
   365  
   366  			pr, repo, err := f.Find(FindOptions{
   367  				Selector:   tt.args.selector,
   368  				Fields:     tt.args.fields,
   369  				BaseBranch: tt.args.baseBranch,
   370  			})
   371  			if (err != nil) != tt.wantErr {
   372  				t.Errorf("Find() error = %v, wantErr %v", err, tt.wantErr)
   373  				return
   374  			}
   375  			if tt.wantErr {
   376  				if tt.wantPR > 0 {
   377  					t.Error("wantPR field is not checked in error case")
   378  				}
   379  				if tt.wantRepo != "" {
   380  					t.Error("wantRepo field is not checked in error case")
   381  				}
   382  				return
   383  			}
   384  
   385  			if pr.Number != tt.wantPR {
   386  				t.Errorf("want pr #%d, got #%d", tt.wantPR, pr.Number)
   387  			}
   388  			repoURL := ghrepo.GenerateRepoURL(repo, "")
   389  			if repoURL != tt.wantRepo {
   390  				t.Errorf("want repo %s, got %s", tt.wantRepo, repoURL)
   391  			}
   392  		})
   393  	}
   394  }