From 6ff326bf5fad4e1fa033220d2a91a87b781348e1 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 12:23:27 -0400 Subject: [PATCH 1/9] consume type param --- cmd/sandbox/delete_test.go | 10 ++++---- cmd/sandbox/list.go | 16 +++++++++---- cmd/sandbox/list_test.go | 31 ++++++++++++------------ internal/api/api_mock.go | 4 ++-- internal/api/sandbox.go | 7 ++++-- internal/api/sandbox_test.go | 10 ++++---- internal/shared/types/sandbox.go | 4 ++-- scripts/install-prerelease.sh | 41 ++++++++++++++++++++++++++++++++ 8 files changed, 87 insertions(+), 36 deletions(-) create mode 100755 scripts/install-prerelease.sh diff --git a/cmd/sandbox/delete_test.go b/cmd/sandbox/delete_test.go index d12d43a3..9b6fb273 100644 --- a/cmd/sandbox/delete_test.go +++ b/cmd/sandbox/delete_test.go @@ -40,7 +40,7 @@ func TestDeleteCommand(t *testing.T) { cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") cm.API.On("DeleteSandbox", mock.Anything, testToken, "T123").Return(nil) - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -49,7 +49,7 @@ func TestDeleteCommand(t *testing.T) { ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.Auth.AssertCalled(t, "AuthWithToken", mock.Anything, "xoxb-test-token") cm.API.AssertCalled(t, "DeleteSandbox", mock.Anything, "xoxb-test-token", "T123") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") }, }, "delete with remaining sandboxes": { @@ -74,7 +74,7 @@ func TestDeleteCommand(t *testing.T) { DateArchived: 0, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -82,7 +82,7 @@ func TestDeleteCommand(t *testing.T) { ExpectedStdoutOutputs: []string{"Sandbox Deleted", "T123", "other-sandbox", "T456"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.API.AssertCalled(t, "DeleteSandbox", mock.Anything, "xoxb-test-token", "T123") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") }, }, "deletion cancelled": { @@ -117,7 +117,7 @@ func TestDeleteCommand(t *testing.T) { cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") cm.IO.On("ConfirmPrompt", mock.Anything, "Are you sure you want to delete the sandbox?", false).Return(true, nil) cm.API.On("DeleteSandbox", mock.Anything, testToken, "E0123456").Return(nil) - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() diff --git a/cmd/sandbox/list.go b/cmd/sandbox/list.go index 5809c88e..9a34e838 100644 --- a/cmd/sandbox/list.go +++ b/cmd/sandbox/list.go @@ -26,7 +26,8 @@ import ( ) type listFlags struct { - status string + status string + sandboxType string } var listCmdFlags listFlags @@ -44,6 +45,7 @@ func NewListCommand(clients *shared.ClientFactory) *cobra.Command { Example: style.ExampleCommandsf([]style.ExampleCommand{ {Command: "sandbox list", Meaning: "List developer sandboxes"}, {Command: "sandbox list --status active", Meaning: "List active sandboxes only"}, + {Command: "sandbox list --type basic", Meaning: "List basic sandboxes only"}, }), RunE: func(cmd *cobra.Command, args []string) error { return runListCommand(cmd, clients) @@ -51,6 +53,7 @@ func NewListCommand(clients *shared.ClientFactory) *cobra.Command { } cmd.Flags().StringVar(&listCmdFlags.status, "status", "", "Filter by status: active, archived") + cmd.Flags().StringVar(&listCmdFlags.sandboxType, "type", "", "Filter by type: basic, regular, partner") return cmd } @@ -75,7 +78,7 @@ func runListCommand(cmd *cobra.Command, clients *shared.ClientFactory) error { func printSandboxes(cmd *cobra.Command, clients *shared.ClientFactory, token string, auth *types.SlackAuth) error { ctx := cmd.Context() - sandboxes, err := clients.API().ListSandboxes(ctx, token, listCmdFlags.status) + sandboxes, err := clients.API().ListSandboxes(ctx, token, listCmdFlags.status, listCmdFlags.sandboxType) if err != nil { return err } @@ -113,12 +116,15 @@ func printSandboxes(cmd *cobra.Command, clients *shared.ClientFactory, token str clients.IO.PrintInfo(ctx, false, " %s", style.Secondary(fmt.Sprintf("URL: https://%s.slack.com", s.Domain))) } - if s.IsPartner { - clients.IO.PrintInfo(ctx, false, " %s", style.Secondary("Type: Partner")) + switch s.Type { + case "basic": + clients.IO.PrintInfo(ctx, false, " %s", style.Secondary("Type: basic")) + case "partner": + clients.IO.PrintInfo(ctx, false, " %s", style.Secondary("Type: partner")) } if s.Status != "" { - status := style.Secondary(fmt.Sprintf("Status: %s", strings.ToTitle(s.Status))) + status := style.Secondary(fmt.Sprintf("Status: %s", strings.ToLower(s.Status))) if strings.EqualFold(s.Status, "archived") { clients.IO.PrintInfo(ctx, false, " %s", style.Red(status)) } else { diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index f7e3386d..4765dbf5 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -36,7 +36,7 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -44,7 +44,7 @@ func TestListCommand(t *testing.T) { ExpectedStdoutOutputs: []string{"No sandboxes found"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.Auth.AssertCalled(t, "AuthWithToken", mock.Anything, "xoxb-test-token") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") }, }, "with active sandboxes": { @@ -64,14 +64,14 @@ func TestListCommand(t *testing.T) { DateArchived: 0, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: ACTIVE"}, + ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") assert.NotContains(t, cm.GetStdoutOutput(), "Type:") }, }, @@ -92,14 +92,14 @@ func TestListCommand(t *testing.T) { DateArchived: 1710000000, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"old-sandbox", "T456", "Status: ARCHIVED"}, + ExpectedStdoutOutputs: []string{"old-sandbox", "T456", "Status: archived"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") }, }, "with partner sandbox shows type for all sandboxes": { @@ -116,6 +116,7 @@ func TestListCommand(t *testing.T) { Domain: "regular-sandbox", Status: "active", DateCreated: 1700000000, + Type: "regular", }, { TeamID: "T789", @@ -123,17 +124,17 @@ func TestListCommand(t *testing.T) { Domain: "partner-sandbox", Status: "active", DateCreated: 1700000000, - IsPartner: true, + Type: "partner", }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"regular-sandbox", "partner-sandbox", "Type: Partner"}, + ExpectedStdoutOutputs: []string{"regular-sandbox", "partner-sandbox", "Type: partner"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") }, }, "with status": { @@ -143,13 +144,13 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "active").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "active", "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "active") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "active", "") }, }, "list error": { @@ -159,7 +160,7 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, ""). + cm.API.On("ListSandboxes", mock.Anything, testToken, "", ""). Return([]types.Sandbox(nil), errors.New("api_error")) cm.AddDefaultMocks() diff --git a/internal/api/api_mock.go b/internal/api/api_mock.go index 7dbb330b..5601b030 100644 --- a/internal/api/api_mock.go +++ b/internal/api/api_mock.go @@ -225,8 +225,8 @@ func (m *APIMock) DeleteSandbox(ctx context.Context, token, sandboxID string) er return args.Error(0) } -func (m *APIMock) ListSandboxes(ctx context.Context, token string, filter string) ([]types.Sandbox, error) { - args := m.Called(ctx, token, filter) +func (m *APIMock) ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) { + args := m.Called(ctx, token, status, sandboxType) return args.Get(0).([]types.Sandbox), args.Error(1) } diff --git a/internal/api/sandbox.go b/internal/api/sandbox.go index 2bd88915..d7726678 100644 --- a/internal/api/sandbox.go +++ b/internal/api/sandbox.go @@ -35,7 +35,7 @@ const ( type SandboxClient interface { CreateSandbox(ctx context.Context, token, name, domain, password, locale, owningOrgID string, templateID int, eventCode string, archiveDate int64, isPartner bool) (teamID, sandboxURL string, err error) DeleteSandbox(ctx context.Context, token, sandboxID string) error - ListSandboxes(ctx context.Context, token string, filter string) ([]types.Sandbox, error) + ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) } type createSandboxResponse struct { @@ -127,7 +127,7 @@ func (c *Client) DeleteSandbox(ctx context.Context, token, sandboxID string) err } // ListSandboxes returns all sandboxes owned by the Developer Account with an email address that matches the authenticated user -func (c *Client) ListSandboxes(ctx context.Context, token string, status string) ([]types.Sandbox, error) { +func (c *Client) ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) { var span opentracing.Span span, ctx = opentracing.StartSpanFromContext(ctx, "apiclient.ListSandboxes") defer span.Finish() @@ -137,6 +137,9 @@ func (c *Client) ListSandboxes(ctx context.Context, token string, status string) if status != "" { values.Add("status", status) } + if sandboxType != "" { + values.Add("type", sandboxType) + } b, err := c.postForm(ctx, sandboxListMethod, values) if err != nil { diff --git a/internal/api/sandbox_test.go b/internal/api/sandbox_test.go index 1798f351..9dc139a5 100644 --- a/internal/api/sandbox_test.go +++ b/internal/api/sandbox_test.go @@ -81,7 +81,7 @@ func TestClient_ListSandboxes_Ok(t *testing.T) { Response: `{"ok":true,"sandboxes":[{"sandbox_team_id":"T1","sandbox_name":"Sandbox 1","sandbox_domain":"sb1","status":"active","date_created":123,"date_archived":0},{"sandbox_team_id":"T2","sandbox_name":"Sandbox 2","sandbox_domain":"sb2","status":"active","date_created":456,"date_archived":0}]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "", "") require.NoError(t, err) require.Len(t, sandboxes, 2) require.Equal(t, "T1", sandboxes[0].TeamID) @@ -98,7 +98,7 @@ func TestClient_ListSandboxes_Empty(t *testing.T) { Response: `{"ok":true,"sandboxes":[]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "", "") require.NoError(t, err) require.Empty(t, sandboxes) } @@ -110,7 +110,7 @@ func TestClient_ListSandboxes_NilSandboxesReturnsEmptySlice(t *testing.T) { Response: `{"ok":true}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "", "") require.NoError(t, err) require.Equal(t, []types.Sandbox{}, sandboxes) } @@ -122,7 +122,7 @@ func TestClient_ListSandboxes_WithStatusFilter(t *testing.T) { Response: `{"ok":true,"sandboxes":[{"sandbox_team_id":"T1","sandbox_name":"Archived","sandbox_domain":"arch","status":"archived","date_created":100,"date_archived":200}]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "archived") + sandboxes, err := c.ListSandboxes(ctx, "token", "archived", "") require.NoError(t, err) require.Len(t, sandboxes, 1) require.Equal(t, "archived", sandboxes[0].Status) @@ -131,7 +131,7 @@ func TestClient_ListSandboxes_WithStatusFilter(t *testing.T) { func TestClient_ListSandboxes_CommonErrors(t *testing.T) { ctx := slackcontext.MockContext(t.Context()) verifyCommonErrorCases(t, sandboxListMethod, func(c *Client) error { - _, err := c.ListSandboxes(ctx, "token", "") + _, err := c.ListSandboxes(ctx, "token", "", "") return err }) } diff --git a/internal/shared/types/sandbox.go b/internal/shared/types/sandbox.go index 7385fe2e..b2d93a2e 100644 --- a/internal/shared/types/sandbox.go +++ b/internal/shared/types/sandbox.go @@ -21,6 +21,6 @@ type Sandbox struct { Domain string `json:"sandbox_domain"` Name string `json:"sandbox_name"` TeamID string `json:"sandbox_team_id"` - Status string `json:"status"` - IsPartner bool `json:"is_partner"` + Status string `json:"status"` + Type string `json:"type"` } diff --git a/scripts/install-prerelease.sh b/scripts/install-prerelease.sh new file mode 100755 index 00000000..5108cff2 --- /dev/null +++ b/scripts/install-prerelease.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# Install the latest Slack CLI pre-release from GitHub + +set -e + +RELEASE_TAG="${1:-latest}" +CLI_NAME="${2:-slack-prerelease}" + +# Get the latest pre-release if "latest" is specified +if [ "$RELEASE_TAG" = "latest" ]; then + RELEASE_TAG=$(curl -s https://api.github.com/repos/slackapi/slack-cli/releases | grep -m 1 '"tag_name"' | grep -v 'v[0-9]*\.[0-9]*\.[0-9]*"' | cut -d'"' -f4) +fi + +# Determine platform and architecture +if [ "$(uname)" = "Darwin" ]; then + ARCH=$(uname -m) + [ "$ARCH" = "arm64" ] && ARCH="arm64" || ARCH="amd64" + PLATFORM="macOS" +else + PLATFORM="linux" + ARCH="64-bit" +fi + +# Download and extract +INSTALL_DIR="$HOME/.slack/prerelease" +mkdir -p "$INSTALL_DIR" + +echo "📥 Downloading $RELEASE_TAG for $PLATFORM $ARCH..." +curl -fsSL "https://github.com/slackapi/slack-cli/releases/download/$RELEASE_TAG/slack_cli_*_${PLATFORM}_${ARCH}.tar.gz" -o "$INSTALL_DIR/slack-cli.tar.gz" 2>/dev/null || \ + curl -fsSL "https://github.com/slackapi/slack-cli/releases/download/$RELEASE_TAG/slack_cli_*_${PLATFORM}_64-bit.tar.gz" -o "$INSTALL_DIR/slack-cli.tar.gz" + +tar -xzf "$INSTALL_DIR/slack-cli.tar.gz" -C "$INSTALL_DIR" +chmod +x "$INSTALL_DIR/bin/slack" +rm "$INSTALL_DIR/slack-cli.tar.gz" + +# Create symlink +mkdir -p "$HOME/.local/bin" +ln -sf "$INSTALL_DIR/bin/slack" "$HOME/.local/bin/$CLI_NAME" + +echo "✅ Installed $CLI_NAME" +echo "🔍 Version: $($HOME/.local/bin/$CLI_NAME --version)" From 7febd0e3612ec68d45401bc3e83f890d745d1257 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 13:51:58 -0400 Subject: [PATCH 2/9] rm type filter for now --- cmd/sandbox/delete_test.go | 10 ++++----- cmd/sandbox/list.go | 7 ++---- cmd/sandbox/list_test.go | 22 +++++++++---------- internal/api/api_mock.go | 4 ++-- internal/api/sandbox.go | 7 ++---- internal/api/sandbox_test.go | 10 ++++----- scripts/install-prerelease.sh | 41 ----------------------------------- 7 files changed, 27 insertions(+), 74 deletions(-) delete mode 100755 scripts/install-prerelease.sh diff --git a/cmd/sandbox/delete_test.go b/cmd/sandbox/delete_test.go index 9b6fb273..d12d43a3 100644 --- a/cmd/sandbox/delete_test.go +++ b/cmd/sandbox/delete_test.go @@ -40,7 +40,7 @@ func TestDeleteCommand(t *testing.T) { cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") cm.API.On("DeleteSandbox", mock.Anything, testToken, "T123").Return(nil) - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -49,7 +49,7 @@ func TestDeleteCommand(t *testing.T) { ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.Auth.AssertCalled(t, "AuthWithToken", mock.Anything, "xoxb-test-token") cm.API.AssertCalled(t, "DeleteSandbox", mock.Anything, "xoxb-test-token", "T123") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, "delete with remaining sandboxes": { @@ -74,7 +74,7 @@ func TestDeleteCommand(t *testing.T) { DateArchived: 0, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -82,7 +82,7 @@ func TestDeleteCommand(t *testing.T) { ExpectedStdoutOutputs: []string{"Sandbox Deleted", "T123", "other-sandbox", "T456"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.API.AssertCalled(t, "DeleteSandbox", mock.Anything, "xoxb-test-token", "T123") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, "deletion cancelled": { @@ -117,7 +117,7 @@ func TestDeleteCommand(t *testing.T) { cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") cm.IO.On("ConfirmPrompt", mock.Anything, "Are you sure you want to delete the sandbox?", false).Return(true, nil) cm.API.On("DeleteSandbox", mock.Anything, testToken, "E0123456").Return(nil) - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() diff --git a/cmd/sandbox/list.go b/cmd/sandbox/list.go index 9a34e838..3cd3d89b 100644 --- a/cmd/sandbox/list.go +++ b/cmd/sandbox/list.go @@ -26,8 +26,7 @@ import ( ) type listFlags struct { - status string - sandboxType string + status string } var listCmdFlags listFlags @@ -45,7 +44,6 @@ func NewListCommand(clients *shared.ClientFactory) *cobra.Command { Example: style.ExampleCommandsf([]style.ExampleCommand{ {Command: "sandbox list", Meaning: "List developer sandboxes"}, {Command: "sandbox list --status active", Meaning: "List active sandboxes only"}, - {Command: "sandbox list --type basic", Meaning: "List basic sandboxes only"}, }), RunE: func(cmd *cobra.Command, args []string) error { return runListCommand(cmd, clients) @@ -53,7 +51,6 @@ func NewListCommand(clients *shared.ClientFactory) *cobra.Command { } cmd.Flags().StringVar(&listCmdFlags.status, "status", "", "Filter by status: active, archived") - cmd.Flags().StringVar(&listCmdFlags.sandboxType, "type", "", "Filter by type: basic, regular, partner") return cmd } @@ -78,7 +75,7 @@ func runListCommand(cmd *cobra.Command, clients *shared.ClientFactory) error { func printSandboxes(cmd *cobra.Command, clients *shared.ClientFactory, token string, auth *types.SlackAuth) error { ctx := cmd.Context() - sandboxes, err := clients.API().ListSandboxes(ctx, token, listCmdFlags.status, listCmdFlags.sandboxType) + sandboxes, err := clients.API().ListSandboxes(ctx, token, listCmdFlags.status) if err != nil { return err } diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index 4765dbf5..c213da39 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -36,7 +36,7 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() @@ -44,7 +44,7 @@ func TestListCommand(t *testing.T) { ExpectedStdoutOutputs: []string{"No sandboxes found"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.Auth.AssertCalled(t, "AuthWithToken", mock.Anything, "xoxb-test-token") - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, "with active sandboxes": { @@ -64,14 +64,14 @@ func TestListCommand(t *testing.T) { DateArchived: 0, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") assert.NotContains(t, cm.GetStdoutOutput(), "Type:") }, }, @@ -92,14 +92,14 @@ func TestListCommand(t *testing.T) { DateArchived: 1710000000, }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, ExpectedStdoutOutputs: []string{"old-sandbox", "T456", "Status: archived"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, "with partner sandbox shows type for all sandboxes": { @@ -127,14 +127,14 @@ func TestListCommand(t *testing.T) { Type: "partner", }, } - cm.API.On("ListSandboxes", mock.Anything, testToken, "", "").Return(sandboxes, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, ExpectedStdoutOutputs: []string{"regular-sandbox", "partner-sandbox", "Type: partner"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, "with status": { @@ -144,13 +144,13 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "active", "").Return([]types.Sandbox{}, nil) + cm.API.On("ListSandboxes", mock.Anything, testToken, "active").Return([]types.Sandbox{}, nil) cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) cm.AddDefaultMocks() }, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "active", "") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "active") }, }, "list error": { @@ -160,7 +160,7 @@ func TestListCommand(t *testing.T) { cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "", ""). + cm.API.On("ListSandboxes", mock.Anything, testToken, ""). Return([]types.Sandbox(nil), errors.New("api_error")) cm.AddDefaultMocks() diff --git a/internal/api/api_mock.go b/internal/api/api_mock.go index 5601b030..564348d1 100644 --- a/internal/api/api_mock.go +++ b/internal/api/api_mock.go @@ -225,8 +225,8 @@ func (m *APIMock) DeleteSandbox(ctx context.Context, token, sandboxID string) er return args.Error(0) } -func (m *APIMock) ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) { - args := m.Called(ctx, token, status, sandboxType) +func (m *APIMock) ListSandboxes(ctx context.Context, token string, status string) ([]types.Sandbox, error) { + args := m.Called(ctx, token, status) return args.Get(0).([]types.Sandbox), args.Error(1) } diff --git a/internal/api/sandbox.go b/internal/api/sandbox.go index d7726678..80613429 100644 --- a/internal/api/sandbox.go +++ b/internal/api/sandbox.go @@ -35,7 +35,7 @@ const ( type SandboxClient interface { CreateSandbox(ctx context.Context, token, name, domain, password, locale, owningOrgID string, templateID int, eventCode string, archiveDate int64, isPartner bool) (teamID, sandboxURL string, err error) DeleteSandbox(ctx context.Context, token, sandboxID string) error - ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) + ListSandboxes(ctx context.Context, token string, status string) ([]types.Sandbox, error) } type createSandboxResponse struct { @@ -127,7 +127,7 @@ func (c *Client) DeleteSandbox(ctx context.Context, token, sandboxID string) err } // ListSandboxes returns all sandboxes owned by the Developer Account with an email address that matches the authenticated user -func (c *Client) ListSandboxes(ctx context.Context, token string, status string, sandboxType string) ([]types.Sandbox, error) { +func (c *Client) ListSandboxes(ctx context.Context, token string, status string) ([]types.Sandbox, error) { var span opentracing.Span span, ctx = opentracing.StartSpanFromContext(ctx, "apiclient.ListSandboxes") defer span.Finish() @@ -137,9 +137,6 @@ func (c *Client) ListSandboxes(ctx context.Context, token string, status string, if status != "" { values.Add("status", status) } - if sandboxType != "" { - values.Add("type", sandboxType) - } b, err := c.postForm(ctx, sandboxListMethod, values) if err != nil { diff --git a/internal/api/sandbox_test.go b/internal/api/sandbox_test.go index 9dc139a5..1798f351 100644 --- a/internal/api/sandbox_test.go +++ b/internal/api/sandbox_test.go @@ -81,7 +81,7 @@ func TestClient_ListSandboxes_Ok(t *testing.T) { Response: `{"ok":true,"sandboxes":[{"sandbox_team_id":"T1","sandbox_name":"Sandbox 1","sandbox_domain":"sb1","status":"active","date_created":123,"date_archived":0},{"sandbox_team_id":"T2","sandbox_name":"Sandbox 2","sandbox_domain":"sb2","status":"active","date_created":456,"date_archived":0}]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "") require.NoError(t, err) require.Len(t, sandboxes, 2) require.Equal(t, "T1", sandboxes[0].TeamID) @@ -98,7 +98,7 @@ func TestClient_ListSandboxes_Empty(t *testing.T) { Response: `{"ok":true,"sandboxes":[]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "") require.NoError(t, err) require.Empty(t, sandboxes) } @@ -110,7 +110,7 @@ func TestClient_ListSandboxes_NilSandboxesReturnsEmptySlice(t *testing.T) { Response: `{"ok":true}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "") require.NoError(t, err) require.Equal(t, []types.Sandbox{}, sandboxes) } @@ -122,7 +122,7 @@ func TestClient_ListSandboxes_WithStatusFilter(t *testing.T) { Response: `{"ok":true,"sandboxes":[{"sandbox_team_id":"T1","sandbox_name":"Archived","sandbox_domain":"arch","status":"archived","date_created":100,"date_archived":200}]}`, }) defer teardown() - sandboxes, err := c.ListSandboxes(ctx, "token", "archived", "") + sandboxes, err := c.ListSandboxes(ctx, "token", "archived") require.NoError(t, err) require.Len(t, sandboxes, 1) require.Equal(t, "archived", sandboxes[0].Status) @@ -131,7 +131,7 @@ func TestClient_ListSandboxes_WithStatusFilter(t *testing.T) { func TestClient_ListSandboxes_CommonErrors(t *testing.T) { ctx := slackcontext.MockContext(t.Context()) verifyCommonErrorCases(t, sandboxListMethod, func(c *Client) error { - _, err := c.ListSandboxes(ctx, "token", "", "") + _, err := c.ListSandboxes(ctx, "token", "") return err }) } diff --git a/scripts/install-prerelease.sh b/scripts/install-prerelease.sh deleted file mode 100755 index 5108cff2..00000000 --- a/scripts/install-prerelease.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Install the latest Slack CLI pre-release from GitHub - -set -e - -RELEASE_TAG="${1:-latest}" -CLI_NAME="${2:-slack-prerelease}" - -# Get the latest pre-release if "latest" is specified -if [ "$RELEASE_TAG" = "latest" ]; then - RELEASE_TAG=$(curl -s https://api.github.com/repos/slackapi/slack-cli/releases | grep -m 1 '"tag_name"' | grep -v 'v[0-9]*\.[0-9]*\.[0-9]*"' | cut -d'"' -f4) -fi - -# Determine platform and architecture -if [ "$(uname)" = "Darwin" ]; then - ARCH=$(uname -m) - [ "$ARCH" = "arm64" ] && ARCH="arm64" || ARCH="amd64" - PLATFORM="macOS" -else - PLATFORM="linux" - ARCH="64-bit" -fi - -# Download and extract -INSTALL_DIR="$HOME/.slack/prerelease" -mkdir -p "$INSTALL_DIR" - -echo "📥 Downloading $RELEASE_TAG for $PLATFORM $ARCH..." -curl -fsSL "https://github.com/slackapi/slack-cli/releases/download/$RELEASE_TAG/slack_cli_*_${PLATFORM}_${ARCH}.tar.gz" -o "$INSTALL_DIR/slack-cli.tar.gz" 2>/dev/null || \ - curl -fsSL "https://github.com/slackapi/slack-cli/releases/download/$RELEASE_TAG/slack_cli_*_${PLATFORM}_64-bit.tar.gz" -o "$INSTALL_DIR/slack-cli.tar.gz" - -tar -xzf "$INSTALL_DIR/slack-cli.tar.gz" -C "$INSTALL_DIR" -chmod +x "$INSTALL_DIR/bin/slack" -rm "$INSTALL_DIR/slack-cli.tar.gz" - -# Create symlink -mkdir -p "$HOME/.local/bin" -ln -sf "$INSTALL_DIR/bin/slack" "$HOME/.local/bin/$CLI_NAME" - -echo "✅ Installed $CLI_NAME" -echo "🔍 Version: $($HOME/.local/bin/$CLI_NAME --version)" From 9a961ebe5d1008567fe3172b6adc928aa1af694d Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 15:43:11 -0400 Subject: [PATCH 3/9] lint --- internal/shared/types/sandbox.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/shared/types/sandbox.go b/internal/shared/types/sandbox.go index b2d93a2e..346aaed4 100644 --- a/internal/shared/types/sandbox.go +++ b/internal/shared/types/sandbox.go @@ -21,6 +21,6 @@ type Sandbox struct { Domain string `json:"sandbox_domain"` Name string `json:"sandbox_name"` TeamID string `json:"sandbox_team_id"` - Status string `json:"status"` - Type string `json:"type"` + Status string `json:"status"` + Type string `json:"type"` } From 883690a568800c5550cb1a3107e8980802d63f4d Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 16:48:00 -0400 Subject: [PATCH 4/9] update test --- cmd/sandbox/list_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index c213da39..480c615b 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -62,6 +62,16 @@ func TestListCommand(t *testing.T) { Status: "active", DateCreated: 1700000000, DateArchived: 0, + Type: "regular", + }, + { + TeamID: "T456", + Name: "basic-sandbox", + Domain: "basic-sandbox", + Status: "active", + DateCreated: 1700000000, + DateArchived: 0, + Type: "basic", }, } cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) @@ -69,7 +79,7 @@ func TestListCommand(t *testing.T) { cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active"}, + ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active", "basic-sandbox", "T456"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") assert.NotContains(t, cm.GetStdoutOutput(), "Type:") From 1290a0e22effd46450698d91c01e63874077f972 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 17:29:21 -0400 Subject: [PATCH 5/9] fix test --- cmd/sandbox/list_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index 480c615b..e5c8ee72 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -23,7 +23,6 @@ import ( "github.com/slackapi/slack-cli/internal/shared/types" "github.com/slackapi/slack-cli/test/testutil" "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -79,10 +78,9 @@ func TestListCommand(t *testing.T) { cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active", "basic-sandbox", "T456"}, + ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active", "basic-sandbox", "T456", "Type: basic"}, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") - assert.NotContains(t, cm.GetStdoutOutput(), "Type:") }, }, "with archived sandbox": { From 909ddeb043c4257231c633fd1e5f85d26b685fa0 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 17:35:21 -0400 Subject: [PATCH 6/9] update list API output for this test as well --- cmd/sandbox/list_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index e5c8ee72..d8ebec31 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -98,6 +98,7 @@ func TestListCommand(t *testing.T) { Status: "archived", DateCreated: 1700000000, DateArchived: 1710000000, + Type: "regular", }, } cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) From 6e535a6e82d870ad01a5e891040a3ae0ebe73ae6 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 17:40:54 -0400 Subject: [PATCH 7/9] don't need to incl experiment flag --- cmd/sandbox/list_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index d8ebec31..c0026204 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -112,7 +112,7 @@ func TestListCommand(t *testing.T) { }, }, "with partner sandbox shows type for all sandboxes": { - CmdArgs: []string{"--experiment=sandboxes", "--token", "xoxb-test-token"}, + CmdArgs: []string{"--token", "xoxb-test-token"}, Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { testToken := "xoxb-test-token" cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) From c3e25c92a0048b31ceaf1fc0380a2eb97e77fc1b Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 18:05:38 -0400 Subject: [PATCH 8/9] refactor tests a bit --- cmd/sandbox/list_test.go | 105 +++++++-------------------------------- 1 file changed, 19 insertions(+), 86 deletions(-) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index c0026204..e22a2cb1 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -23,6 +23,7 @@ import ( "github.com/slackapi/slack-cli/internal/shared/types" "github.com/slackapi/slack-cli/test/testutil" "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -46,93 +47,36 @@ func TestListCommand(t *testing.T) { cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") }, }, - "with active sandboxes": { + "with multiple sandboxes": { CmdArgs: []string{"--token", "xoxb-test-token"}, Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { testToken := "xoxb-test-token" cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - sandboxes := []types.Sandbox{ - { - TeamID: "T123", - Name: "my-sandbox", - Domain: "my-sandbox", - Status: "active", - DateCreated: 1700000000, - DateArchived: 0, - Type: "regular", - }, - { - TeamID: "T456", - Name: "basic-sandbox", - Domain: "basic-sandbox", - Status: "active", - DateCreated: 1700000000, - DateArchived: 0, - Type: "basic", - }, - } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) - cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) - - cm.AddDefaultMocks() - }, - ExpectedStdoutOutputs: []string{"my-sandbox", "T123", "https://my-sandbox.slack.com", "Status: active", "basic-sandbox", "T456", "Type: basic"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") - }, - }, - "with archived sandbox": { - CmdArgs: []string{"--token", "xoxb-test-token"}, - Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { - testToken := "xoxb-test-token" - cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) - cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") - cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - sandboxes := []types.Sandbox{ - { - TeamID: "T456", - Name: "old-sandbox", - Domain: "old-sandbox", - Status: "archived", - DateCreated: 1700000000, - DateArchived: 1710000000, - Type: "regular", - }, - } - cm.API.On("ListSandboxes", mock.Anything, testToken, "").Return(sandboxes, nil) - cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) - - cm.AddDefaultMocks() - }, - ExpectedStdoutOutputs: []string{"old-sandbox", "T456", "Status: archived"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") - }, - }, - "with partner sandbox shows type for all sandboxes": { - CmdArgs: []string{"--token", "xoxb-test-token"}, - Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { - testToken := "xoxb-test-token" - cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) - cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") - cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") sandboxes := []types.Sandbox{ { TeamID: "T123", Name: "regular-sandbox", Domain: "regular-sandbox", Status: "active", - DateCreated: 1700000000, + DateCreated: 1700001000, Type: "regular", }, + { + TeamID: "T456", + Name: "basic-sandbox", + Domain: "basic-sandbox", + Status: "active", + DateCreated: 1700002000, + Type: "basic", + }, { TeamID: "T789", Name: "partner-sandbox", Domain: "partner-sandbox", Status: "active", - DateCreated: 1700000000, + DateCreated: 1700003000, Type: "partner", }, } @@ -141,28 +85,17 @@ func TestListCommand(t *testing.T) { cm.AddDefaultMocks() }, - ExpectedStdoutOutputs: []string{"regular-sandbox", "partner-sandbox", "Type: partner"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") - }, - }, - "with status": { - CmdArgs: []string{"--token", "xoxb-test-token", "--status", "active"}, - Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { - testToken := "xoxb-test-token" - cm.Auth.On("AuthWithToken", mock.Anything, testToken).Return(types.SlackAuth{Token: testToken}, nil) - cm.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("https://api.slack.com") - cm.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything).Return("https://slackb.com/events/cli") - cm.API.On("ListSandboxes", mock.Anything, testToken, "active").Return([]types.Sandbox{}, nil) - cm.API.On("UsersInfo", mock.Anything, mock.Anything, mock.Anything).Return(&types.UserInfo{Profile: types.UserProfile{}}, nil) - - cm.AddDefaultMocks() + ExpectedStdoutOutputs: []string{ + "regular-sandbox", "T123", + "basic-sandbox", "T456", "Type: basic", + "partner-sandbox", "T789", "Type: partner", }, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "active") + cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") + assert.NotContains(t, cm.GetStdoutOutput(), "Type: regular") }, }, - "list error": { + "with an error from the list API": { CmdArgs: []string{"--token", "xoxb-test-token"}, Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { testToken := "xoxb-test-token" From 1809689f1d154a4545fca04e07528778c0e17308 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 8 Oct 2026 18:12:28 -0400 Subject: [PATCH 9/9] update test expectation again --- cmd/sandbox/list_test.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/sandbox/list_test.go b/cmd/sandbox/list_test.go index e22a2cb1..6923f6dc 100644 --- a/cmd/sandbox/list_test.go +++ b/cmd/sandbox/list_test.go @@ -23,7 +23,6 @@ import ( "github.com/slackapi/slack-cli/internal/shared/types" "github.com/slackapi/slack-cli/test/testutil" "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -67,7 +66,7 @@ func TestListCommand(t *testing.T) { TeamID: "T456", Name: "basic-sandbox", Domain: "basic-sandbox", - Status: "active", + Status: "archived", DateCreated: 1700002000, Type: "basic", }, @@ -86,13 +85,12 @@ func TestListCommand(t *testing.T) { cm.AddDefaultMocks() }, ExpectedStdoutOutputs: []string{ - "regular-sandbox", "T123", - "basic-sandbox", "T456", "Type: basic", - "partner-sandbox", "T789", "Type: partner", + "regular-sandbox (T123)\n URL: https://regular-sandbox.slack.com\n Status: active", + "basic-sandbox (T456)\n URL: https://basic-sandbox.slack.com\n Type: basic\n Status: archived", + "partner-sandbox (T789)\n URL: https://partner-sandbox.slack.com\n Type: partner\n Status: active", }, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { cm.API.AssertCalled(t, "ListSandboxes", mock.Anything, "xoxb-test-token", "") - assert.NotContains(t, cm.GetStdoutOutput(), "Type: regular") }, }, "with an error from the list API": {