1import { afterEach, describe, expect, it, vi } from "vite-plus/test";
2
3import {
4 buildConnectCliClerkAuthorizeUrl,
5 connectCliSignInRedirectUrl,
6 hasConnectCliAuthConfig,
7} from "./connectCliAuth";
8
9// Any pk_test_* key decodes to <base64 hostname>.clerk.accounts.dev.
10const TEST_PUBLISHABLE_KEY = `pk_test_${btoa("witty-mole-42.clerk.accounts.dev$")}`;
11
12describe("connectCliAuth", () => {
13 afterEach(() => {
14 vi.unstubAllEnvs();
15 });
16
17 it("requires both the publishable key and the CLI OAuth client id", () => {
18 vi.stubEnv("VITE_CLERK_PUBLISHABLE_KEY", TEST_PUBLISHABLE_KEY);
19 vi.stubEnv("VITE_CLERK_JWT_TEMPLATE", "t3-relay");
20 vi.stubEnv("VITE_T3CODE_RELAY_URL", "https://relay.example.com");
21 expect(hasConnectCliAuthConfig()).toBe(false);
22
23 vi.stubEnv("VITE_CLERK_CLI_OAUTH_CLIENT_ID", "oauthapp_123");
24 expect(hasConnectCliAuthConfig()).toBe(true);
25 });
26
27 it("builds a PKCE authorize URL that redirects to the CLI's loopback listener", () => {
28 vi.stubEnv("VITE_CLERK_PUBLISHABLE_KEY", TEST_PUBLISHABLE_KEY);
29 vi.stubEnv("VITE_CLERK_CLI_OAUTH_CLIENT_ID", "oauthapp_123");
30
31 const authorizeUrl = buildConnectCliClerkAuthorizeUrl({
32 state: "state-1",
33 challenge: "challenge-1",
34 loopbackPort: 34338,
35 });
36 expect(authorizeUrl).not.toBeNull();
37
38 const url = new URL(authorizeUrl!);
39 expect(url.hostname).toBe("witty-mole-42.clerk.accounts.dev");
40 expect(url.pathname).toBe("/oauth/authorize");
41 expect(url.searchParams.get("redirect_uri")).toBe("http://127.0.0.1:34338/callback");
42 expect(url.searchParams.get("state")).toBe("state-1");
43 expect(url.searchParams.get("code_challenge")).toBe("challenge-1");
44 expect(url.searchParams.get("code_challenge_method")).toBe("S256");
45 });
46
47 it("returns null when the CLI OAuth client id is not configured", () => {
48 vi.stubEnv("VITE_CLERK_PUBLISHABLE_KEY", TEST_PUBLISHABLE_KEY);
49 expect(
50 buildConnectCliClerkAuthorizeUrl({
51 state: "state-1",
52 challenge: "challenge-1",
53 loopbackPort: 34338,
54 }),
55 ).toBeNull();
56 });
57
58 it("sends the sign-in redirect to the authorize endpoint, not back to /connect", () => {
59 vi.stubEnv("VITE_CLERK_PUBLISHABLE_KEY", TEST_PUBLISHABLE_KEY);
60 vi.stubEnv("VITE_CLERK_CLI_OAUTH_CLIENT_ID", "oauthapp_123");
61
62 const connectUrl =
63 "https://app.t3.codes/connect#state=state-1&challenge=challenge-1&port=34338";
64 const redirectUrl = connectCliSignInRedirectUrl(
65 { state: "state-1", challenge: "challenge-1", loopbackPort: 34338 },
66 connectUrl,
67 );
68
69 expect(redirectUrl).not.toBe(connectUrl);
70 expect(new URL(redirectUrl).pathname).toBe("/oauth/authorize");
71 });
72
73 it("falls back to the current URL when the authorize URL cannot be built", () => {
74 vi.stubEnv("VITE_CLERK_PUBLISHABLE_KEY", TEST_PUBLISHABLE_KEY);
75
76 const connectUrl =
77 "https://app.t3.codes/connect#state=state-1&challenge=challenge-1&port=34338";
78 expect(
79 connectCliSignInRedirectUrl(
80 { state: "state-1", challenge: "challenge-1", loopbackPort: 34338 },
81 connectUrl,
82 ),
83 ).toBe(connectUrl);
84 });
85});