github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/pr/comment/comment_test.go (about)

     1  package comment
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/andrewhsu/cli/v2/api"
    12  	"github.com/andrewhsu/cli/v2/internal/ghrepo"
    13  	"github.com/andrewhsu/cli/v2/pkg/cmd/pr/shared"
    14  	"github.com/andrewhsu/cli/v2/pkg/cmdutil"
    15  	"github.com/andrewhsu/cli/v2/pkg/httpmock"
    16  	"github.com/andrewhsu/cli/v2/pkg/iostreams"
    17  	"github.com/google/shlex"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestNewCmdComment(t *testing.T) {
    23  	tmpFile := filepath.Join(t.TempDir(), "my-body.md")
    24  	err := ioutil.WriteFile(tmpFile, []byte("a body from file"), 0600)
    25  	require.NoError(t, err)
    26  
    27  	tests := []struct {
    28  		name     string
    29  		input    string
    30  		stdin    string
    31  		output   shared.CommentableOptions
    32  		wantsErr bool
    33  	}{
    34  		{
    35  			name:  "no arguments",
    36  			input: "",
    37  			output: shared.CommentableOptions{
    38  				Interactive: true,
    39  				InputType:   0,
    40  				Body:        "",
    41  			},
    42  			wantsErr: false,
    43  		},
    44  		{
    45  			name:     "two arguments",
    46  			input:    "1 2",
    47  			output:   shared.CommentableOptions{},
    48  			wantsErr: true,
    49  		},
    50  		{
    51  			name:  "pr number",
    52  			input: "1",
    53  			output: shared.CommentableOptions{
    54  				Interactive: true,
    55  				InputType:   0,
    56  				Body:        "",
    57  			},
    58  			wantsErr: false,
    59  		},
    60  		{
    61  			name:  "pr url",
    62  			input: "https://github.com/OWNER/REPO/pull/12",
    63  			output: shared.CommentableOptions{
    64  				Interactive: true,
    65  				InputType:   0,
    66  				Body:        "",
    67  			},
    68  			wantsErr: false,
    69  		},
    70  		{
    71  			name:  "pr branch",
    72  			input: "branch-name",
    73  			output: shared.CommentableOptions{
    74  				Interactive: true,
    75  				InputType:   0,
    76  				Body:        "",
    77  			},
    78  			wantsErr: false,
    79  		},
    80  		{
    81  			name:  "body flag",
    82  			input: "1 --body test",
    83  			output: shared.CommentableOptions{
    84  				Interactive: false,
    85  				InputType:   shared.InputTypeInline,
    86  				Body:        "test",
    87  			},
    88  			wantsErr: false,
    89  		},
    90  		{
    91  			name:  "body from stdin",
    92  			input: "1 --body-file -",
    93  			stdin: "this is on standard input",
    94  			output: shared.CommentableOptions{
    95  				Interactive: false,
    96  				InputType:   shared.InputTypeInline,
    97  				Body:        "this is on standard input",
    98  			},
    99  			wantsErr: false,
   100  		},
   101  		{
   102  			name:  "body from file",
   103  			input: fmt.Sprintf("1 --body-file '%s'", tmpFile),
   104  			output: shared.CommentableOptions{
   105  				Interactive: false,
   106  				InputType:   shared.InputTypeInline,
   107  				Body:        "a body from file",
   108  			},
   109  			wantsErr: false,
   110  		},
   111  		{
   112  			name:  "editor flag",
   113  			input: "1 --editor",
   114  			output: shared.CommentableOptions{
   115  				Interactive: false,
   116  				InputType:   shared.InputTypeEditor,
   117  				Body:        "",
   118  			},
   119  			wantsErr: false,
   120  		},
   121  		{
   122  			name:  "web flag",
   123  			input: "1 --web",
   124  			output: shared.CommentableOptions{
   125  				Interactive: false,
   126  				InputType:   shared.InputTypeWeb,
   127  				Body:        "",
   128  			},
   129  			wantsErr: false,
   130  		},
   131  		{
   132  			name:     "body and body-file flags",
   133  			input:    "1 --body 'test' --body-file 'test-file.txt'",
   134  			output:   shared.CommentableOptions{},
   135  			wantsErr: true,
   136  		},
   137  		{
   138  			name:     "editor and web flags",
   139  			input:    "1 --editor --web",
   140  			output:   shared.CommentableOptions{},
   141  			wantsErr: true,
   142  		},
   143  		{
   144  			name:     "editor and body flags",
   145  			input:    "1 --editor --body test",
   146  			output:   shared.CommentableOptions{},
   147  			wantsErr: true,
   148  		},
   149  		{
   150  			name:     "web and body flags",
   151  			input:    "1 --web --body test",
   152  			output:   shared.CommentableOptions{},
   153  			wantsErr: true,
   154  		},
   155  		{
   156  			name:     "editor, web, and body flags",
   157  			input:    "1 --editor --web --body test",
   158  			output:   shared.CommentableOptions{},
   159  			wantsErr: true,
   160  		},
   161  	}
   162  
   163  	for _, tt := range tests {
   164  		t.Run(tt.name, func(t *testing.T) {
   165  			io, stdin, _, _ := iostreams.Test()
   166  			io.SetStdoutTTY(true)
   167  			io.SetStdinTTY(true)
   168  			io.SetStderrTTY(true)
   169  
   170  			if tt.stdin != "" {
   171  				_, _ = stdin.WriteString(tt.stdin)
   172  			}
   173  
   174  			f := &cmdutil.Factory{
   175  				IOStreams: io,
   176  				Browser:   &cmdutil.TestBrowser{},
   177  			}
   178  
   179  			argv, err := shlex.Split(tt.input)
   180  			assert.NoError(t, err)
   181  
   182  			var gotOpts *shared.CommentableOptions
   183  			cmd := NewCmdComment(f, func(opts *shared.CommentableOptions) error {
   184  				gotOpts = opts
   185  				return nil
   186  			})
   187  			cmd.Flags().BoolP("help", "x", false, "")
   188  
   189  			cmd.SetArgs(argv)
   190  			cmd.SetIn(&bytes.Buffer{})
   191  			cmd.SetOut(&bytes.Buffer{})
   192  			cmd.SetErr(&bytes.Buffer{})
   193  
   194  			_, err = cmd.ExecuteC()
   195  			if tt.wantsErr {
   196  				assert.Error(t, err)
   197  				return
   198  			}
   199  
   200  			assert.NoError(t, err)
   201  			assert.Equal(t, tt.output.Interactive, gotOpts.Interactive)
   202  			assert.Equal(t, tt.output.InputType, gotOpts.InputType)
   203  			assert.Equal(t, tt.output.Body, gotOpts.Body)
   204  		})
   205  	}
   206  }
   207  
   208  func Test_commentRun(t *testing.T) {
   209  	tests := []struct {
   210  		name      string
   211  		input     *shared.CommentableOptions
   212  		httpStubs func(*testing.T, *httpmock.Registry)
   213  		stdout    string
   214  		stderr    string
   215  	}{
   216  		{
   217  			name: "interactive editor",
   218  			input: &shared.CommentableOptions{
   219  				Interactive: true,
   220  				InputType:   0,
   221  				Body:        "",
   222  
   223  				InteractiveEditSurvey: func() (string, error) { return "comment body", nil },
   224  				ConfirmSubmitSurvey:   func() (bool, error) { return true, nil },
   225  			},
   226  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   227  				mockCommentCreate(t, reg)
   228  			},
   229  			stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n",
   230  		},
   231  		{
   232  			name: "non-interactive web",
   233  			input: &shared.CommentableOptions{
   234  				Interactive: false,
   235  				InputType:   shared.InputTypeWeb,
   236  				Body:        "",
   237  
   238  				OpenInBrowser: func(string) error { return nil },
   239  			},
   240  			stderr: "Opening github.com/OWNER/REPO/pull/123 in your browser.\n",
   241  		},
   242  		{
   243  			name: "non-interactive editor",
   244  			input: &shared.CommentableOptions{
   245  				Interactive: false,
   246  				InputType:   shared.InputTypeEditor,
   247  				Body:        "",
   248  
   249  				EditSurvey: func() (string, error) { return "comment body", nil },
   250  			},
   251  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   252  				mockCommentCreate(t, reg)
   253  			},
   254  			stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n",
   255  		},
   256  		{
   257  			name: "non-interactive inline",
   258  			input: &shared.CommentableOptions{
   259  				Interactive: false,
   260  				InputType:   shared.InputTypeInline,
   261  				Body:        "comment body",
   262  			},
   263  			httpStubs: func(t *testing.T, reg *httpmock.Registry) {
   264  				mockCommentCreate(t, reg)
   265  			},
   266  			stdout: "https://github.com/OWNER/REPO/pull/123#issuecomment-456\n",
   267  		},
   268  	}
   269  	for _, tt := range tests {
   270  		io, _, stdout, stderr := iostreams.Test()
   271  		io.SetStdoutTTY(true)
   272  		io.SetStdinTTY(true)
   273  		io.SetStderrTTY(true)
   274  
   275  		reg := &httpmock.Registry{}
   276  		defer reg.Verify(t)
   277  		if tt.httpStubs != nil {
   278  			tt.httpStubs(t, reg)
   279  		}
   280  
   281  		httpClient := func() (*http.Client, error) { return &http.Client{Transport: reg}, nil }
   282  
   283  		tt.input.IO = io
   284  		tt.input.HttpClient = httpClient
   285  		tt.input.RetrieveCommentable = func() (shared.Commentable, ghrepo.Interface, error) {
   286  			return &api.PullRequest{
   287  				Number: 123,
   288  				URL:    "https://github.com/OWNER/REPO/pull/123",
   289  			}, ghrepo.New("OWNER", "REPO"), nil
   290  		}
   291  
   292  		t.Run(tt.name, func(t *testing.T) {
   293  			err := shared.CommentableRun(tt.input)
   294  			assert.NoError(t, err)
   295  			assert.Equal(t, tt.stdout, stdout.String())
   296  			assert.Equal(t, tt.stderr, stderr.String())
   297  		})
   298  	}
   299  }
   300  
   301  func mockCommentCreate(t *testing.T, reg *httpmock.Registry) {
   302  	reg.Register(
   303  		httpmock.GraphQL(`mutation CommentCreate\b`),
   304  		httpmock.GraphQLMutation(`
   305  		{ "data": { "addComment": { "commentEdge": { "node": {
   306  			"url": "https://github.com/OWNER/REPO/pull/123#issuecomment-456"
   307  		} } } } }`,
   308  			func(inputs map[string]interface{}) {
   309  				assert.Equal(t, "comment body", inputs["body"])
   310  			}),
   311  	)
   312  }