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

     1  package list
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net/http"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/MakeNowJust/heredoc"
    12  	"github.com/ungtb10d/cli/v2/internal/browser"
    13  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    14  	"github.com/ungtb10d/cli/v2/internal/run"
    15  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    16  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    17  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    18  	"github.com/ungtb10d/cli/v2/test"
    19  	"github.com/google/shlex"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
    24  	ios, _, stdout, stderr := iostreams.Test()
    25  	ios.SetStdoutTTY(isTTY)
    26  	ios.SetStdinTTY(isTTY)
    27  	ios.SetStderrTTY(isTTY)
    28  
    29  	browser := &browser.Stub{}
    30  	factory := &cmdutil.Factory{
    31  		IOStreams: ios,
    32  		Browser:   browser,
    33  		HttpClient: func() (*http.Client, error) {
    34  			return &http.Client{Transport: rt}, nil
    35  		},
    36  		BaseRepo: func() (ghrepo.Interface, error) {
    37  			return ghrepo.New("OWNER", "REPO"), nil
    38  		},
    39  	}
    40  
    41  	fakeNow := func() time.Time {
    42  		return time.Date(2022, time.August, 24, 23, 50, 0, 0, time.UTC)
    43  	}
    44  
    45  	cmd := NewCmdList(factory, func(opts *ListOptions) error {
    46  		opts.Now = fakeNow
    47  		return listRun(opts)
    48  	})
    49  
    50  	argv, err := shlex.Split(cli)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	cmd.SetArgs(argv)
    55  
    56  	cmd.SetIn(&bytes.Buffer{})
    57  	cmd.SetOut(io.Discard)
    58  	cmd.SetErr(io.Discard)
    59  
    60  	_, err = cmd.ExecuteC()
    61  	return &test.CmdOut{
    62  		OutBuf:     stdout,
    63  		ErrBuf:     stderr,
    64  		BrowsedURL: browser.BrowsedURL(),
    65  	}, err
    66  }
    67  
    68  func initFakeHTTP() *httpmock.Registry {
    69  	return &httpmock.Registry{}
    70  }
    71  
    72  func TestPRList(t *testing.T) {
    73  	http := initFakeHTTP()
    74  	defer http.Verify(t)
    75  
    76  	http.Register(httpmock.GraphQL(`query PullRequestList\b`), httpmock.FileResponse("./fixtures/prList.json"))
    77  
    78  	output, err := runCommand(http, true, "")
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	assert.Equal(t, heredoc.Doc(`
    84  
    85  		Showing 3 of 3 open pull requests in OWNER/REPO
    86  
    87  		#32  New feature            feature        about 3 hours ago
    88  		#29  Fixed bad bug          hubot:bug-fix  about 1 month ago
    89  		#28  Improve documentation  docs           about 2 years ago
    90  	`), output.String())
    91  	assert.Equal(t, ``, output.Stderr())
    92  }
    93  
    94  func TestPRList_nontty(t *testing.T) {
    95  	http := initFakeHTTP()
    96  	defer http.Verify(t)
    97  
    98  	http.Register(httpmock.GraphQL(`query PullRequestList\b`), httpmock.FileResponse("./fixtures/prList.json"))
    99  
   100  	output, err := runCommand(http, false, "")
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	assert.Equal(t, "", output.Stderr())
   106  
   107  	assert.Equal(t, `32	New feature	feature	DRAFT	2022-08-24 20:01:12 +0000 UTC
   108  29	Fixed bad bug	hubot:bug-fix	OPEN	2022-07-20 19:01:12 +0000 UTC
   109  28	Improve documentation	docs	MERGED	2020-01-26 19:01:12 +0000 UTC
   110  `, output.String())
   111  }
   112  
   113  func TestPRList_filtering(t *testing.T) {
   114  	http := initFakeHTTP()
   115  	defer http.Verify(t)
   116  
   117  	http.Register(
   118  		httpmock.GraphQL(`query PullRequestList\b`),
   119  		httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   120  			assert.Equal(t, []interface{}{"OPEN", "CLOSED", "MERGED"}, params["state"].([]interface{}))
   121  		}))
   122  
   123  	output, err := runCommand(http, true, `-s all`)
   124  	assert.Error(t, err)
   125  
   126  	assert.Equal(t, "", output.String())
   127  	assert.Equal(t, "", output.Stderr())
   128  }
   129  
   130  func TestPRList_filteringRemoveDuplicate(t *testing.T) {
   131  	http := initFakeHTTP()
   132  	defer http.Verify(t)
   133  
   134  	http.Register(
   135  		httpmock.GraphQL(`query PullRequestList\b`),
   136  		httpmock.FileResponse("./fixtures/prListWithDuplicates.json"))
   137  
   138  	output, err := runCommand(http, true, "")
   139  	if err != nil {
   140  		t.Fatal(err)
   141  	}
   142  
   143  	out := output.String()
   144  	idx := strings.Index(out, "New feature")
   145  	if idx < 0 {
   146  		t.Fatalf("text %q not found in %q", "New feature", out)
   147  	}
   148  	assert.Equal(t, idx, strings.LastIndex(out, "New feature"))
   149  }
   150  
   151  func TestPRList_filteringClosed(t *testing.T) {
   152  	http := initFakeHTTP()
   153  	defer http.Verify(t)
   154  
   155  	http.Register(
   156  		httpmock.GraphQL(`query PullRequestList\b`),
   157  		httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   158  			assert.Equal(t, []interface{}{"CLOSED", "MERGED"}, params["state"].([]interface{}))
   159  		}))
   160  
   161  	_, err := runCommand(http, true, `-s closed`)
   162  	assert.Error(t, err)
   163  }
   164  
   165  func TestPRList_filteringHeadBranch(t *testing.T) {
   166  	http := initFakeHTTP()
   167  	defer http.Verify(t)
   168  
   169  	http.Register(
   170  		httpmock.GraphQL(`query PullRequestList\b`),
   171  		httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   172  			assert.Equal(t, interface{}("bug-fix"), params["headBranch"])
   173  		}))
   174  
   175  	_, err := runCommand(http, true, `-H bug-fix`)
   176  	assert.Error(t, err)
   177  }
   178  
   179  func TestPRList_filteringAssignee(t *testing.T) {
   180  	http := initFakeHTTP()
   181  	defer http.Verify(t)
   182  
   183  	http.Register(
   184  		httpmock.GraphQL(`query PullRequestSearch\b`),
   185  		httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   186  			assert.Equal(t, `assignee:hubot base:develop is:merged label:"needs tests" repo:OWNER/REPO type:pr`, params["q"].(string))
   187  		}))
   188  
   189  	_, err := runCommand(http, true, `-s merged -l "needs tests" -a hubot -B develop`)
   190  	assert.Error(t, err)
   191  }
   192  
   193  func TestPRList_filteringDraft(t *testing.T) {
   194  	tests := []struct {
   195  		name          string
   196  		cli           string
   197  		expectedQuery string
   198  	}{
   199  		{
   200  			name:          "draft",
   201  			cli:           "--draft",
   202  			expectedQuery: `draft:true repo:OWNER/REPO state:open type:pr`,
   203  		},
   204  		{
   205  			name:          "non-draft",
   206  			cli:           "--draft=false",
   207  			expectedQuery: `draft:false repo:OWNER/REPO state:open type:pr`,
   208  		},
   209  	}
   210  
   211  	for _, test := range tests {
   212  		t.Run(test.name, func(t *testing.T) {
   213  			http := initFakeHTTP()
   214  			defer http.Verify(t)
   215  
   216  			http.Register(
   217  				httpmock.GraphQL(`query PullRequestSearch\b`),
   218  				httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   219  					assert.Equal(t, test.expectedQuery, params["q"].(string))
   220  				}))
   221  
   222  			_, err := runCommand(http, true, test.cli)
   223  			assert.Error(t, err)
   224  		})
   225  	}
   226  }
   227  
   228  func TestPRList_filteringAuthor(t *testing.T) {
   229  	tests := []struct {
   230  		name          string
   231  		cli           string
   232  		expectedQuery string
   233  	}{
   234  		{
   235  			name:          "author @me",
   236  			cli:           `--author "@me"`,
   237  			expectedQuery: `author:@me repo:OWNER/REPO state:open type:pr`,
   238  		},
   239  		{
   240  			name:          "author user",
   241  			cli:           `--author "monalisa"`,
   242  			expectedQuery: `author:monalisa repo:OWNER/REPO state:open type:pr`,
   243  		},
   244  		{
   245  			name:          "app author",
   246  			cli:           `--author "app/dependabot"`,
   247  			expectedQuery: `author:app/dependabot repo:OWNER/REPO state:open type:pr`,
   248  		},
   249  		{
   250  			name:          "app author with app option",
   251  			cli:           `--app "dependabot"`,
   252  			expectedQuery: `author:app/dependabot repo:OWNER/REPO state:open type:pr`,
   253  		},
   254  	}
   255  
   256  	for _, test := range tests {
   257  		t.Run(test.name, func(t *testing.T) {
   258  			http := initFakeHTTP()
   259  			defer http.Verify(t)
   260  
   261  			http.Register(
   262  				httpmock.GraphQL(`query PullRequestSearch\b`),
   263  				httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   264  					assert.Equal(t, test.expectedQuery, params["q"].(string))
   265  				}))
   266  
   267  			_, err := runCommand(http, true, test.cli)
   268  			assert.Error(t, err)
   269  		})
   270  	}
   271  }
   272  
   273  func TestPRList_withInvalidLimitFlag(t *testing.T) {
   274  	http := initFakeHTTP()
   275  	defer http.Verify(t)
   276  	_, err := runCommand(http, true, `--limit=0`)
   277  	assert.EqualError(t, err, "invalid value for --limit: 0")
   278  }
   279  
   280  func TestPRList_web(t *testing.T) {
   281  	tests := []struct {
   282  		name               string
   283  		cli                string
   284  		expectedBrowserURL string
   285  	}{
   286  		{
   287  			name:               "filters",
   288  			cli:                "-a peter -l bug -l docs -L 10 -s merged -B trunk",
   289  			expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=assignee%3Apeter+base%3Atrunk+is%3Amerged+label%3Abug+label%3Adocs+type%3Apr",
   290  		},
   291  		{
   292  			name:               "draft",
   293  			cli:                "--draft=true",
   294  			expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=draft%3Atrue+state%3Aopen+type%3Apr",
   295  		},
   296  		{
   297  			name:               "non-draft",
   298  			cli:                "--draft=0",
   299  			expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=draft%3Afalse+state%3Aopen+type%3Apr",
   300  		},
   301  	}
   302  
   303  	for _, test := range tests {
   304  		t.Run(test.name, func(t *testing.T) {
   305  			http := initFakeHTTP()
   306  			defer http.Verify(t)
   307  
   308  			_, cmdTeardown := run.Stub()
   309  			defer cmdTeardown(t)
   310  
   311  			output, err := runCommand(http, true, "--web "+test.cli)
   312  			if err != nil {
   313  				t.Errorf("error running command `pr list` with `--web` flag: %v", err)
   314  			}
   315  
   316  			assert.Equal(t, "", output.String())
   317  			assert.Equal(t, "Opening github.com/OWNER/REPO/pulls in your browser.\n", output.Stderr())
   318  			assert.Equal(t, test.expectedBrowserURL, output.BrowsedURL)
   319  		})
   320  	}
   321  }