749 lines
15 KiB
Go
749 lines
15 KiB
Go
package view
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/cli/cli/v2/internal/prompter"
|
|
"github.com/cli/cli/v2/pkg/cmd/project/shared/queries"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/google/shlex"
|
|
"github.com/stretchr/testify/assert"
|
|
"gopkg.in/h2non/gock.v1"
|
|
)
|
|
|
|
func TestNewCmdview(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cli string
|
|
wants viewOpts
|
|
wantsErr bool
|
|
wantsErrMsg string
|
|
wantsExporter bool
|
|
}{
|
|
{
|
|
name: "not-a-number",
|
|
cli: "x",
|
|
wantsErr: true,
|
|
wantsErrMsg: "invalid number: x",
|
|
},
|
|
{
|
|
name: "number",
|
|
cli: "123",
|
|
wants: viewOpts{
|
|
number: 123,
|
|
},
|
|
},
|
|
{
|
|
name: "owner",
|
|
cli: "--owner monalisa",
|
|
wants: viewOpts{
|
|
owner: "monalisa",
|
|
},
|
|
},
|
|
{
|
|
name: "web",
|
|
cli: "--web",
|
|
wants: viewOpts{
|
|
web: true,
|
|
},
|
|
},
|
|
{
|
|
name: "json",
|
|
cli: "--format json",
|
|
wantsExporter: true,
|
|
},
|
|
}
|
|
|
|
t.Setenv("GH_TOKEN", "auth-token")
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ios, _, _, _ := iostreams.Test()
|
|
f := &cmdutil.Factory{
|
|
IOStreams: ios,
|
|
}
|
|
|
|
argv, err := shlex.Split(tt.cli)
|
|
assert.NoError(t, err)
|
|
|
|
var gotOpts viewOpts
|
|
cmd := NewCmdView(f, func(config viewConfig) error {
|
|
gotOpts = config.opts
|
|
return nil
|
|
})
|
|
|
|
cmd.SetArgs(argv)
|
|
_, err = cmd.ExecuteC()
|
|
if tt.wantsErr {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.wantsErrMsg, err.Error())
|
|
return
|
|
}
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, tt.wants.number, gotOpts.number)
|
|
assert.Equal(t, tt.wants.owner, gotOpts.owner)
|
|
assert.Equal(t, tt.wantsExporter, gotOpts.exporter != nil)
|
|
assert.Equal(t, tt.wants.web, gotOpts.web)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunView_User(t *testing.T) {
|
|
defer gock.Off()
|
|
|
|
// get user ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query UserOrgOwner.*",
|
|
"variables": map[string]interface{}{
|
|
"login": "monalisa",
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"user": map[string]interface{}{
|
|
"id": "an ID",
|
|
},
|
|
},
|
|
"errors": []interface{}{
|
|
map[string]interface{}{
|
|
"type": "NOT_FOUND",
|
|
"path": []string{"organization"},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"user":
|
|
{
|
|
"login":"monalisa",
|
|
"projectV2": {
|
|
"number": 1,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"readme": null,
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "monalisa",
|
|
number: 1,
|
|
},
|
|
io: ios,
|
|
client: client,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
func TestRunView_Viewer(t *testing.T) {
|
|
defer gock.Off()
|
|
|
|
// get viewer ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query ViewerOwner.*",
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"viewer": map[string]interface{}{
|
|
"id": "an ID",
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"viewer":
|
|
{
|
|
"login":"monalisa",
|
|
"projectV2": {
|
|
"number": 1,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"url":"https://github.com/orgs/github/projects/8",
|
|
"readme": null,
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "@me",
|
|
number: 1,
|
|
},
|
|
io: ios,
|
|
client: client,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRunView_Org(t *testing.T) {
|
|
defer gock.Off()
|
|
|
|
// get org ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query UserOrgOwner.*",
|
|
"variables": map[string]interface{}{
|
|
"login": "github",
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"organization": map[string]interface{}{
|
|
"id": "an ID",
|
|
},
|
|
},
|
|
"errors": []interface{}{
|
|
map[string]interface{}{
|
|
"type": "NOT_FOUND",
|
|
"path": []string{"user"},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"organization":
|
|
{
|
|
"login":"monalisa",
|
|
"projectV2": {
|
|
"number": 1,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"url":"https://github.com/orgs/github/projects/8",
|
|
"readme": null,
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "github",
|
|
number: 1,
|
|
},
|
|
io: ios,
|
|
client: client,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRunViewWeb_User(t *testing.T) {
|
|
defer gock.Off()
|
|
gock.Observe(gock.DumpRequest)
|
|
// get user ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query UserOrgOwner.*",
|
|
"variables": map[string]interface{}{
|
|
"login": "monalisa",
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"user": map[string]interface{}{
|
|
"id": "an ID",
|
|
},
|
|
},
|
|
"errors": []interface{}{
|
|
map[string]interface{}{
|
|
"type": "NOT_FOUND",
|
|
"path": []string{"organization"},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"user":
|
|
{
|
|
"login":"monalisa",
|
|
"projectV2": {
|
|
"number": 8,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"url":"https://github.com/users/monalisa/projects/8",
|
|
"readme": null,
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
buf := bytes.Buffer{}
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "monalisa",
|
|
web: true,
|
|
number: 8,
|
|
},
|
|
URLOpener: func(url string) error {
|
|
buf.WriteString(url)
|
|
return nil
|
|
},
|
|
client: client,
|
|
io: ios,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "https://github.com/users/monalisa/projects/8", buf.String())
|
|
}
|
|
|
|
func TestRunViewWeb_Org(t *testing.T) {
|
|
defer gock.Off()
|
|
gock.Observe(gock.DumpRequest)
|
|
// get org ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query UserOrgOwner.*",
|
|
"variables": map[string]interface{}{
|
|
"login": "github",
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"organization": map[string]interface{}{
|
|
"id": "an ID",
|
|
},
|
|
},
|
|
"errors": []interface{}{
|
|
map[string]interface{}{
|
|
"type": "NOT_FOUND",
|
|
"path": []string{"user"},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"organization":
|
|
{
|
|
"login":"github",
|
|
"projectV2": {
|
|
"number": 8,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"url": "https://github.com/orgs/github/projects/8",
|
|
"readme": null,
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
buf := bytes.Buffer{}
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "github",
|
|
web: true,
|
|
number: 8,
|
|
},
|
|
URLOpener: func(url string) error {
|
|
buf.WriteString(url)
|
|
return nil
|
|
},
|
|
client: client,
|
|
io: ios,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "https://github.com/orgs/github/projects/8", buf.String())
|
|
}
|
|
|
|
func TestRunViewWeb_Me(t *testing.T) {
|
|
defer gock.Off()
|
|
gock.Observe(gock.DumpRequest)
|
|
// get viewer ID
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query Viewer.*",
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"viewer": map[string]interface{}{
|
|
"id": "an ID",
|
|
"login": "theviewer",
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query ViewerProject.*",
|
|
"variables": map[string]interface{}{"afterFields": nil, "afterItems": nil, "firstFields": 100, "firstItems": 0, "number": 8},
|
|
}).
|
|
Reply(200).
|
|
JSON(`
|
|
{"data":
|
|
{"viewer":
|
|
{
|
|
"login":"github",
|
|
"projectV2": {
|
|
"number": 8,
|
|
"items": {
|
|
"totalCount": 10
|
|
},
|
|
"readme": null,
|
|
"url": "https://github.com/users/theviewer/projects/8",
|
|
"fields": {
|
|
"nodes": [
|
|
{
|
|
"name": "Title"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
client := queries.NewTestClient()
|
|
buf := bytes.Buffer{}
|
|
ios, _, _, _ := iostreams.Test()
|
|
config := viewConfig{
|
|
opts: viewOpts{
|
|
owner: "@me",
|
|
web: true,
|
|
number: 8,
|
|
},
|
|
URLOpener: func(url string) error {
|
|
buf.WriteString(url)
|
|
return nil
|
|
},
|
|
client: client,
|
|
io: ios,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "https://github.com/users/theviewer/projects/8", buf.String())
|
|
}
|
|
|
|
func TestRunViewWeb_TTY(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setup func(*viewOpts, *testing.T) func()
|
|
promptStubs func(*prompter.PrompterMock)
|
|
gqlStubs func(*testing.T)
|
|
expectedBrowse string
|
|
tty bool
|
|
}{
|
|
{
|
|
name: "Org project --web with tty",
|
|
tty: true,
|
|
setup: func(vo *viewOpts, t *testing.T) func() {
|
|
return func() {
|
|
vo.web = true
|
|
}
|
|
},
|
|
gqlStubs: func(t *testing.T) {
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query ViewerLoginAndOrgs.*",
|
|
"variables": map[string]interface{}{
|
|
"after": nil,
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"viewer": map[string]interface{}{
|
|
"id": "monalisa-ID",
|
|
"login": "monalisa",
|
|
"organizations": map[string]interface{}{
|
|
"nodes": []interface{}{
|
|
map[string]interface{}{
|
|
"login": "github",
|
|
"viewerCanCreateProjects": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query OrgProjects.*",
|
|
"variables": map[string]interface{}{
|
|
"after": nil,
|
|
"afterFields": nil,
|
|
"afterItems": nil,
|
|
"first": 30,
|
|
"firstFields": 100,
|
|
"firstItems": 0,
|
|
"login": "github",
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"organization": map[string]interface{}{
|
|
"login": "github",
|
|
"projectsV2": map[string]interface{}{
|
|
"nodes": []interface{}{
|
|
map[string]interface{}{
|
|
"id": "a-project-ID",
|
|
"title": "Get it done!",
|
|
"url": "https://github.com/orgs/github/projects/1",
|
|
"number": 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
},
|
|
promptStubs: func(pm *prompter.PrompterMock) {
|
|
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
|
switch prompt {
|
|
case "Which owner would you like to use?":
|
|
return prompter.IndexFor(opts, "github")
|
|
case "Which project would you like to use?":
|
|
return prompter.IndexFor(opts, "Get it done! (#1)")
|
|
default:
|
|
return -1, prompter.NoSuchPromptErr(prompt)
|
|
}
|
|
}
|
|
},
|
|
expectedBrowse: "https://github.com/orgs/github/projects/1",
|
|
},
|
|
{
|
|
name: "User project --web with tty",
|
|
tty: true,
|
|
setup: func(vo *viewOpts, t *testing.T) func() {
|
|
return func() {
|
|
vo.web = true
|
|
}
|
|
},
|
|
gqlStubs: func(t *testing.T) {
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query ViewerLoginAndOrgs.*",
|
|
"variables": map[string]interface{}{
|
|
"after": nil,
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"viewer": map[string]interface{}{
|
|
"id": "monalisa-ID",
|
|
"login": "monalisa",
|
|
"organizations": map[string]interface{}{
|
|
"nodes": []interface{}{
|
|
map[string]interface{}{
|
|
"login": "github",
|
|
"viewerCanCreateProjects": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
gock.New("https://api.github.com").
|
|
Post("/graphql").
|
|
MatchType("json").
|
|
JSON(map[string]interface{}{
|
|
"query": "query ViewerProjects.*",
|
|
"variables": map[string]interface{}{
|
|
"after": nil, "afterFields": nil, "afterItems": nil, "first": 30, "firstFields": 100, "firstItems": 0,
|
|
},
|
|
}).
|
|
Reply(200).
|
|
JSON(map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"viewer": map[string]interface{}{
|
|
"login": "monalisa",
|
|
"projectsV2": map[string]interface{}{
|
|
"totalCount": 1,
|
|
"nodes": []interface{}{
|
|
map[string]interface{}{
|
|
"id": "a-project-ID",
|
|
"number": 1,
|
|
"title": "@monalia's first project",
|
|
"url": "https://github.com/users/monalisa/projects/1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
},
|
|
promptStubs: func(pm *prompter.PrompterMock) {
|
|
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
|
switch prompt {
|
|
case "Which owner would you like to use?":
|
|
return prompter.IndexFor(opts, "monalisa")
|
|
case "Which project would you like to use?":
|
|
return prompter.IndexFor(opts, "@monalia's first project (#1)")
|
|
default:
|
|
return -1, prompter.NoSuchPromptErr(prompt)
|
|
}
|
|
}
|
|
},
|
|
expectedBrowse: "https://github.com/users/monalisa/projects/1",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
defer gock.Off()
|
|
gock.Observe(gock.DumpRequest)
|
|
|
|
if tt.gqlStubs != nil {
|
|
tt.gqlStubs(t)
|
|
}
|
|
|
|
pm := &prompter.PrompterMock{}
|
|
if tt.promptStubs != nil {
|
|
tt.promptStubs(pm)
|
|
}
|
|
|
|
opts := viewOpts{}
|
|
if tt.setup != nil {
|
|
tt.setup(&opts, t)()
|
|
}
|
|
|
|
ios, _, _, _ := iostreams.Test()
|
|
ios.SetStdoutTTY(tt.tty)
|
|
ios.SetStdinTTY(tt.tty)
|
|
ios.SetStderrTTY(tt.tty)
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
client := queries.NewTestClient(queries.WithPrompter(pm))
|
|
|
|
config := viewConfig{
|
|
opts: opts,
|
|
URLOpener: func(url string) error {
|
|
_, err := buf.WriteString(url)
|
|
return err
|
|
},
|
|
client: client,
|
|
io: ios,
|
|
}
|
|
|
|
err := runView(config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.expectedBrowse, buf.String())
|
|
})
|
|
}
|
|
}
|