Skip to content

Commit 9b2f6f2

Browse files
authored
chore: unit tests for vanity subdomain (#4829)
* chore: unit tests for vanity subdomain * chore: check flag error
1 parent aa62c12 commit 9b2f6f2

9 files changed

Lines changed: 334 additions & 70 deletions

File tree

cmd/vanitySubdomains.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@ After the vanity subdomain is activated, your project's auth services will no lo
6464
func init() {
6565
vanityCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.")
6666
vanityActivateCmd.Flags().StringVar(&desiredSubdomain, "desired-subdomain", "", "The desired vanity subdomain to use for your Supabase project.")
67+
cobra.CheckErr(vanityActivateCmd.MarkFlagRequired("desired-subdomain"))
6768
vanityCheckCmd.Flags().StringVar(&desiredSubdomain, "desired-subdomain", "", "The desired vanity subdomain to use for your Supabase project.")
69+
cobra.CheckErr(vanityCheckCmd.MarkFlagRequired("desired-subdomain"))
6870
vanityCmd.AddCommand(vanityGetCmd)
6971
vanityCmd.AddCommand(vanityCheckCmd)
7072
vanityCmd.AddCommand(vanityActivateCmd)
7173
vanityCmd.AddCommand(vanityDeleteCmd)
72-
7374
rootCmd.AddCommand(vanityCmd)
7475
}

internal/vanity_subdomains/activate/activate.go

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package activate
33
import (
44
"context"
55
"fmt"
6-
"strings"
6+
"os"
77

88
"github.com/go-errors/errors"
99
"github.com/spf13/afero"
@@ -12,26 +12,17 @@ import (
1212
)
1313

1414
func Run(ctx context.Context, projectRef string, desiredSubdomain string, fsys afero.Fs) error {
15-
// 1. Sanity checks.
16-
subdomain := strings.TrimSpace(desiredSubdomain)
17-
{
18-
if len(subdomain) == 0 {
19-
return errors.New("non-empty vanity subdomain expected")
20-
}
15+
resp, err := utils.GetSupabase().V1ActivateVanitySubdomainConfigWithResponse(ctx, projectRef, api.V1ActivateVanitySubdomainConfigJSONRequestBody{
16+
VanitySubdomain: desiredSubdomain,
17+
})
18+
if err != nil {
19+
return errors.Errorf("failed activate vanity subdomain: %w", err)
20+
} else if resp.JSON201 == nil {
21+
return errors.Errorf("unexpected activate vanity subdomain status %d: %s", resp.StatusCode(), string(resp.Body))
2122
}
22-
23-
// 2. create vanity subdomain
24-
{
25-
resp, err := utils.GetSupabase().V1ActivateVanitySubdomainConfigWithResponse(ctx, projectRef, api.V1ActivateVanitySubdomainConfigJSONRequestBody{
26-
VanitySubdomain: subdomain,
27-
})
28-
if err != nil {
29-
return errors.Errorf("failed activate vanity subdomain: %w", err)
30-
}
31-
if resp.JSON201 == nil {
32-
return errors.New("failed to create vanity subdomain config: " + string(resp.Body))
33-
}
34-
fmt.Printf("Activated vanity subdomain at %s\n", resp.JSON201.CustomDomain)
35-
return nil
23+
if utils.OutputFormat.Value != utils.OutputPretty {
24+
return utils.EncodeOutput(utils.OutputFormat.Value, os.Stdout, *resp.JSON201)
3625
}
26+
fmt.Printf("Activated vanity subdomain at %s\n", resp.JSON201.CustomDomain)
27+
return nil
3728
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package activate
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/go-errors/errors"
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/testing/fstest"
13+
"github.com/supabase/cli/internal/utils"
14+
"github.com/supabase/cli/internal/utils/flags"
15+
"github.com/supabase/cli/pkg/api"
16+
)
17+
18+
func TestActivateSubdomain(t *testing.T) {
19+
t.Run("actives vanity subdomain", func(t *testing.T) {
20+
t.Cleanup(fstest.MockStdout(t, "Activated vanity subdomain at example.com\n"))
21+
t.Cleanup(apitest.MockPlatformAPI(t))
22+
// Setup mock api
23+
gock.New(utils.DefaultApiHost).
24+
Post("v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
25+
Reply(http.StatusCreated).
26+
JSON(api.ActivateVanitySubdomainResponse{
27+
CustomDomain: "example.com",
28+
})
29+
// Run test
30+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
31+
assert.NoError(t, err)
32+
})
33+
34+
t.Run("encodes toml output", func(t *testing.T) {
35+
utils.OutputFormat.Value = utils.OutputToml
36+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
37+
t.Cleanup(fstest.MockStdout(t, `CustomDomain = "example.com"
38+
`))
39+
t.Cleanup(apitest.MockPlatformAPI(t))
40+
// Setup mock api
41+
gock.New(utils.DefaultApiHost).
42+
Post("v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
43+
Reply(http.StatusCreated).
44+
JSON(api.ActivateVanitySubdomainResponse{
45+
CustomDomain: "example.com",
46+
})
47+
// Run test
48+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
49+
assert.NoError(t, err)
50+
})
51+
52+
t.Run("throws error on network error", func(t *testing.T) {
53+
errNetwork := errors.New("network error")
54+
t.Cleanup(apitest.MockPlatformAPI(t))
55+
// Setup mock api
56+
gock.New(utils.DefaultApiHost).
57+
Post("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
58+
ReplyError(errNetwork)
59+
// Run test
60+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
61+
assert.ErrorIs(t, err, errNetwork)
62+
})
63+
64+
t.Run("throws error on service unavailable", func(t *testing.T) {
65+
utils.OutputFormat.Value = utils.OutputEnv
66+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
67+
t.Cleanup(apitest.MockPlatformAPI(t))
68+
// Setup mock api
69+
gock.New(utils.DefaultApiHost).
70+
Post("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
71+
Reply(http.StatusServiceUnavailable)
72+
// Run test
73+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
74+
assert.ErrorContains(t, err, "unexpected activate vanity subdomain status 503:")
75+
})
76+
}

internal/vanity_subdomains/check/check.go

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package check
33
import (
44
"context"
55
"fmt"
6-
"strings"
6+
"os"
77

88
"github.com/go-errors/errors"
99
"github.com/spf13/afero"
@@ -12,26 +12,17 @@ import (
1212
)
1313

1414
func Run(ctx context.Context, projectRef string, desiredSubdomain string, fsys afero.Fs) error {
15-
// 1. Sanity checks.
16-
subdomain := strings.TrimSpace(desiredSubdomain)
17-
{
18-
if len(subdomain) == 0 {
19-
return errors.New("non-empty vanity subdomain expected")
20-
}
15+
resp, err := utils.GetSupabase().V1CheckVanitySubdomainAvailabilityWithResponse(ctx, projectRef, api.V1CheckVanitySubdomainAvailabilityJSONRequestBody{
16+
VanitySubdomain: desiredSubdomain,
17+
})
18+
if err != nil {
19+
return errors.Errorf("failed to check vanity subdomain: %w", err)
20+
} else if resp.JSON201 == nil {
21+
return errors.Errorf("unexpected check vanity subdomain status %d: %s", resp.StatusCode(), string(resp.Body))
2122
}
22-
23-
// 2. check if the subdomain is available
24-
{
25-
resp, err := utils.GetSupabase().V1CheckVanitySubdomainAvailabilityWithResponse(ctx, projectRef, api.V1CheckVanitySubdomainAvailabilityJSONRequestBody{
26-
VanitySubdomain: subdomain,
27-
})
28-
if err != nil {
29-
return errors.Errorf("failed to check vanity subdomain: %w", err)
30-
}
31-
if resp.JSON201 == nil {
32-
return errors.New("failed to check subdomain availability: " + string(resp.Body))
33-
}
34-
fmt.Printf("Subdomain %s available: %+v\n", subdomain, resp.JSON201.Available)
35-
return nil
23+
if utils.OutputFormat.Value != utils.OutputPretty {
24+
return utils.EncodeOutput(utils.OutputFormat.Value, os.Stdout, *resp.JSON201)
3625
}
26+
fmt.Printf("Subdomain %s available: %+v\n", desiredSubdomain, resp.JSON201.Available)
27+
return nil
3728
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package check
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/go-errors/errors"
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/testing/fstest"
13+
"github.com/supabase/cli/internal/utils"
14+
"github.com/supabase/cli/internal/utils/flags"
15+
"github.com/supabase/cli/pkg/api"
16+
)
17+
18+
func TestCheckSubdomain(t *testing.T) {
19+
t.Run("checks subdomain availability", func(t *testing.T) {
20+
t.Cleanup(fstest.MockStdout(t, "Subdomain example.com available: true\n"))
21+
t.Cleanup(apitest.MockPlatformAPI(t))
22+
// Setup mock api
23+
gock.New(utils.DefaultApiHost).
24+
Post("v1/projects/" + flags.ProjectRef + "/vanity-subdomain/check-availability").
25+
Reply(http.StatusCreated).
26+
JSON(api.SubdomainAvailabilityResponse{
27+
Available: true,
28+
})
29+
// Run test
30+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
31+
assert.NoError(t, err)
32+
})
33+
34+
t.Run("encodes toml output", func(t *testing.T) {
35+
utils.OutputFormat.Value = utils.OutputToml
36+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
37+
t.Cleanup(fstest.MockStdout(t, "Available = false\n"))
38+
t.Cleanup(apitest.MockPlatformAPI(t))
39+
// Setup mock api
40+
gock.New(utils.DefaultApiHost).
41+
Post("v1/projects/" + flags.ProjectRef + "/vanity-subdomain/check-availability").
42+
Reply(http.StatusCreated).
43+
JSON(api.SubdomainAvailabilityResponse{})
44+
// Run test
45+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
46+
assert.NoError(t, err)
47+
})
48+
49+
t.Run("throws error on network error", func(t *testing.T) {
50+
errNetwork := errors.New("network error")
51+
t.Cleanup(apitest.MockPlatformAPI(t))
52+
// Setup mock api
53+
gock.New(utils.DefaultApiHost).
54+
Post("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain/check-availability").
55+
ReplyError(errNetwork)
56+
// Run test
57+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
58+
assert.ErrorIs(t, err, errNetwork)
59+
})
60+
61+
t.Run("throws error on service unavailable", func(t *testing.T) {
62+
utils.OutputFormat.Value = utils.OutputEnv
63+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
64+
t.Cleanup(apitest.MockPlatformAPI(t))
65+
// Setup mock api
66+
gock.New(utils.DefaultApiHost).
67+
Post("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain/check-availability").
68+
Reply(http.StatusServiceUnavailable)
69+
// Run test
70+
err := Run(context.Background(), flags.ProjectRef, "example.com", nil)
71+
assert.ErrorContains(t, err, "unexpected check vanity subdomain status 503:")
72+
})
73+
}

internal/vanity_subdomains/delete/delete.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@ package delete
33
import (
44
"context"
55
"fmt"
6+
"net/http"
7+
"os"
68

79
"github.com/go-errors/errors"
810
"github.com/spf13/afero"
911
"github.com/supabase/cli/internal/utils"
1012
)
1113

1214
func Run(ctx context.Context, projectRef string, fsys afero.Fs) error {
13-
// 1. Sanity checks.
14-
// 2. delete config
15-
{
16-
resp, err := utils.GetSupabase().V1DeactivateVanitySubdomainConfigWithResponse(ctx, projectRef)
17-
if err != nil {
18-
return errors.Errorf("failed to delete vanity subdomain: %w", err)
19-
}
20-
if resp.StatusCode() != 200 {
21-
return errors.New("failed to delete vanity subdomain config; received: " + string(resp.Body))
22-
}
23-
fmt.Println("Deleted vanity subdomain successfully.")
24-
return nil
15+
resp, err := utils.GetSupabase().V1DeactivateVanitySubdomainConfigWithResponse(ctx, projectRef)
16+
if err != nil {
17+
return errors.Errorf("failed to delete vanity subdomain: %w", err)
18+
} else if resp.StatusCode() != http.StatusOK {
19+
return errors.Errorf("unexpected delete vanity subdomain status %d: %s", resp.StatusCode(), string(resp.Body))
2520
}
21+
fmt.Fprintln(os.Stderr, "Deleted vanity subdomain successfully.")
22+
return nil
2623
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"errors"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/utils"
13+
"github.com/supabase/cli/internal/utils/flags"
14+
)
15+
16+
func TestDeleteSubdomain(t *testing.T) {
17+
flags.ProjectRef = apitest.RandomProjectRef()
18+
19+
t.Run("deletes vanity subdomain", func(t *testing.T) {
20+
t.Cleanup(apitest.MockPlatformAPI(t))
21+
// Setup mock api
22+
gock.New(utils.DefaultApiHost).
23+
Delete("v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
24+
Reply(http.StatusOK)
25+
// Run test
26+
err := Run(context.Background(), flags.ProjectRef, nil)
27+
assert.NoError(t, err)
28+
})
29+
30+
t.Run("throws error on network error", func(t *testing.T) {
31+
errNetwork := errors.New("network error")
32+
t.Cleanup(apitest.MockPlatformAPI(t))
33+
// Setup mock api
34+
gock.New(utils.DefaultApiHost).
35+
Delete("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
36+
ReplyError(errNetwork)
37+
// Run test
38+
err := Run(context.Background(), flags.ProjectRef, nil)
39+
assert.ErrorIs(t, err, errNetwork)
40+
})
41+
42+
t.Run("throws error on service unavailable", func(t *testing.T) {
43+
utils.OutputFormat.Value = utils.OutputEnv
44+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
45+
t.Cleanup(apitest.MockPlatformAPI(t))
46+
// Setup mock api
47+
gock.New(utils.DefaultApiHost).
48+
Delete("/v1/projects/" + flags.ProjectRef + "/vanity-subdomain").
49+
Reply(http.StatusServiceUnavailable)
50+
// Run test
51+
err := Run(context.Background(), flags.ProjectRef, nil)
52+
assert.ErrorContains(t, err, "unexpected delete vanity subdomain status 503:")
53+
})
54+
}

internal/vanity_subdomains/get/get.go

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,26 @@ package get
33
import (
44
"context"
55
"fmt"
6+
"os"
67

78
"github.com/go-errors/errors"
89
"github.com/spf13/afero"
910
"github.com/supabase/cli/internal/utils"
1011
)
1112

1213
func Run(ctx context.Context, projectRef string, fsys afero.Fs) error {
13-
// 1. Sanity checks.
14-
// 2. get vanity subdomain config
15-
{
16-
response, err := utils.GetSupabase().V1GetVanitySubdomainConfigWithResponse(ctx, projectRef)
17-
if err != nil {
18-
return errors.Errorf("failed to get vanity subdomain: %w", err)
19-
}
20-
if response.JSON200 == nil {
21-
return errors.Errorf("failed to obtain vanity subdomain config: %+v", string(response.Body))
22-
}
23-
fmt.Printf("Status: %s\n", response.JSON200.Status)
24-
if response.JSON200.CustomDomain != nil {
25-
fmt.Printf("Vanity subdomain: %s\n", *response.JSON200.CustomDomain)
26-
}
27-
return nil
14+
resp, err := utils.GetSupabase().V1GetVanitySubdomainConfigWithResponse(ctx, projectRef)
15+
if err != nil {
16+
return errors.Errorf("failed to get vanity subdomain: %w", err)
17+
} else if resp.JSON200 == nil {
18+
return errors.Errorf("unexpected vanity subdomain status %d: %s", resp.StatusCode(), string(resp.Body))
2819
}
20+
if utils.OutputFormat.Value != utils.OutputPretty {
21+
return utils.EncodeOutput(utils.OutputFormat.Value, os.Stdout, *resp.JSON200)
22+
}
23+
fmt.Printf("Status: %s\n", resp.JSON200.Status)
24+
if resp.JSON200.CustomDomain != nil {
25+
fmt.Printf("Vanity subdomain: %s\n", *resp.JSON200.CustomDomain)
26+
}
27+
return nil
2928
}

0 commit comments

Comments
 (0)