From d3fa0a70bcaad7f700db7d2bc63ca01a76b8f56b Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Fri, 5 Sep 2025 12:55:15 +0100 Subject: [PATCH] test(agent-task view): add tests for the `view` command Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/view/view_test.go | 261 +++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 pkg/cmd/agent-task/view/view_test.go diff --git a/pkg/cmd/agent-task/view/view_test.go b/pkg/cmd/agent-task/view/view_test.go new file mode 100644 index 000000000..97304c399 --- /dev/null +++ b/pkg/cmd/agent-task/view/view_test.go @@ -0,0 +1,261 @@ +package view + +import ( + "bytes" + "context" + "errors" + "io" + "testing" + "time" + + "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/v2/api" + "github.com/cli/cli/v2/pkg/cmd/agent-task/capi" + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/iostreams" + "github.com/google/shlex" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewCmdList(t *testing.T) { + tests := []struct { + name string + args string + wantOpts ViewOptions + wantErr string + }{ + { + name: "no arguments", + wantErr: "a session ID is required", + }, + { + name: "session ID arg", + args: "some-uuid", + wantOpts: ViewOptions{ + SelectorArg: "some-uuid", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ios, _, _, _ := iostreams.Test() + f := &cmdutil.Factory{ + IOStreams: ios, + } + + var gotOpts *ViewOptions + cmd := NewCmdView(f, func(opts *ViewOptions) error { gotOpts = opts; return nil }) + + argv, err := shlex.Split(tt.args) + require.NoError(t, err) + cmd.SetArgs(argv) + + cmd.SetIn(&bytes.Buffer{}) + cmd.SetOut(io.Discard) + cmd.SetErr(io.Discard) + + _, err = cmd.ExecuteC() + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + + require.NoError(t, err) + assert.Equal(t, tt.wantOpts.SelectorArg, gotOpts.SelectorArg) + }) + } +} + +func Test_viewRun(t *testing.T) { + sampleDate := time.Now().Add(-6 * time.Hour) // 6h ago + + tests := []struct { + name string + selectorArg string + tty bool + capiStubs func(*testing.T, *capi.CapiClientMock) + wantOut string + wantErr error + wantStderr string + }{ + { + name: "not found (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return nil, capi.ErrSessionNotFound + } + }, + wantStderr: "session not found\n", + wantErr: cmdutil.SilentError, + }, + { + name: "not found (nontty)", + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return nil, capi.ErrSessionNotFound + } + }, + wantStderr: "session not found\n", + wantErr: cmdutil.SilentError, + }, + { + name: "API error (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return nil, errors.New("some error") + } + }, + wantErr: errors.New("some error"), + }, + { + name: "API error (nontty)", + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return nil, errors.New("some error") + } + }, + wantErr: errors.New("some error"), + }, + { + name: "success, with PR and user data (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return &capi.Session{ + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + PullRequest: &api.PullRequest{ + Title: "fix something", + Number: 101, + URL: "https://github.com/OWNER/REPO/pull/101", + Repository: &api.PRRepository{ + NameWithOwner: "OWNER/REPO", + }, + }, + User: &api.GitHubUser{ + Login: "octocat", + }, + }, nil + } + }, + wantOut: heredoc.Doc(` + Completed • fix something • OWNER/REPO#101 + Started on behalf of octocat about 6 hours ago + + View this session on GitHub: + https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id + `), + }, + { + name: "success, without user data (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return &capi.Session{ + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + PullRequest: &api.PullRequest{ + Title: "fix something", + Number: 101, + URL: "https://github.com/OWNER/REPO/pull/101", + Repository: &api.PRRepository{ + NameWithOwner: "OWNER/REPO", + }, + }, + }, nil + } + }, + wantOut: heredoc.Doc(` + Completed • fix something • OWNER/REPO#101 + Started about 6 hours ago + + View this session on GitHub: + https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id + `), + }, + { + name: "success, without PR data (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return &capi.Session{ + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + User: &api.GitHubUser{ + Login: "octocat", + }, + }, nil + } + }, + wantOut: heredoc.Doc(` + Completed + Started on behalf of octocat about 6 hours ago + `), + }, + { + name: "success, without PR nor user data (tty)", + tty: true, + selectorArg: "some-session-id", + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(ctx context.Context, selector string) (*capi.Session, error) { + return &capi.Session{ + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + }, nil + } + }, + wantOut: heredoc.Doc(` + Completed + Started about 6 hours ago + `), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + capiClientMock := &capi.CapiClientMock{} + if tt.capiStubs != nil { + tt.capiStubs(t, capiClientMock) + } + + ios, _, stdout, stderr := iostreams.Test() + ios.SetStdoutTTY(tt.tty) + + opts := &ViewOptions{ + IO: ios, + CapiClient: func() (capi.CapiClient, error) { + return capiClientMock, nil + }, + SelectorArg: tt.selectorArg, + } + + err := viewRun(opts) + if tt.wantErr != nil { + assert.Error(t, err) + require.EqualError(t, err, tt.wantErr.Error()) + } else { + require.NoError(t, err) + } + + got := stdout.String() + require.Equal(t, tt.wantOut, got) + require.Equal(t, tt.wantStderr, stderr.String()) + }) + } +}