import { describe, expect, it } from "@effect/vitest"; import { AuthTemplateSlug, IntegrationSlug, OAuthClientSlug, ProviderItemId, ProviderKey, type Owner, } from "@executor-js/sdk/shared"; import type { AuthMethod } from "../lib/auth-placements"; import { connectionNameFrom, connectionLabel, connectionLabelForHost, createCredentialPayloadOrigin, DEFAULT_CONNECTION_OWNER, mergeCustomMethods, runDcrConnect, } from "./add-account-modal"; const apiKeyMethod = (id: string, source: "spec" | "custom", template = id): AuthMethod => ({ id, label: `API key (${id})`, kind: "apikey", source, template: AuthTemplateSlug.make(template), placements: [{ carrier: "header", name: "Authorization", prefix: "" }], }); type ProbeResult = { readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly scopesSupported?: readonly string[]; readonly registrationEndpoint?: string | null; readonly tokenEndpointAuthMethodsSupported?: readonly string[]; }; type RegisterArgs = { readonly owner: Owner; readonly slug: OAuthClientSlug; readonly registrationEndpoint: string; readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly scopes: readonly string[]; readonly tokenEndpointAuthMethodsSupported?: readonly string[]; readonly clientName: string; readonly redirectUri?: string; readonly originIntegration?: IntegrationSlug; }; type StartArgs = { readonly client: OAuthClientSlug; readonly owner: Owner }; const TEST_INTEGRATION = IntegrationSlug.make("linear_mcp"); describe("connectionLabel (name placeholder derivation)", () => { // The name field is optional but prefilled-via-derivation. With an empty // label this is the derived name shown as the input's placeholder, so the // intent ("leave blank ⇒ use this name") is visible. it("derives ' ' for an empty label (the placeholder)", () => { expect(connectionLabel("", "user", "GitHub")).toBe("Personal GitHub"); expect(connectionLabel("", "org", "GitHub")).toBe("Workspace GitHub"); }); it("treats whitespace-only labels as empty (still derives the placeholder)", () => { expect(connectionLabel(" ", "user", "GitHub")).toBe("Personal GitHub"); }); it("uses the typed label (trimmed) when one is provided", () => { expect(connectionLabel(" My Bot ", "user", "GitHub")).toBe("My Bot"); }); it("uses Local in derived labels for non-org-scoped hosts", () => { expect(connectionLabelForHost("", "org", "GitHub", null)).toBe("Local GitHub"); expect(connectionLabelForHost("", "org", "GitHub", "org_123")).toBe("Workspace GitHub"); }); }); describe("connectionNameFrom", () => { it("derives the JS-callable name from the display name", () => { expect(String(connectionNameFrom("Autumn Production", "user", "Autumn", "org_123"))).toBe( "autumnProduction", ); expect(String(connectionNameFrom("linear-mcp-oauth", "user", "Linear MCP", "org_123"))).toBe( "linearMcpOauth", ); }); it("derives a callable default from owner and integration when the display name is empty", () => { expect(String(connectionNameFrom("", "org", "GitHub", "org_123"))).toBe("workspaceGithub"); expect(String(connectionNameFrom("", "org", "GitHub", null))).toBe("localGithub"); }); }); describe("DEFAULT_CONNECTION_OWNER", () => { // The 'saved to' owner defaults to Personal: a connection is most often a // personal credential. it("defaults a new connection's owner to Personal (user)", () => { expect(DEFAULT_CONNECTION_OWNER).toBe("user"); }); }); describe("mergeCustomMethods (in-session custom method append)", () => { // A just-created custom method joins the selectable list (custom last) so it // can be selected before the catalog refresh lands. it("appends a session-created method after the declared methods", () => { const declared = [apiKeyMethod("spec-1", "spec")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes by stable identity (a refreshed catalog method wins over its session copy)", () => { const declared = [apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a", "custom")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes custom methods by template even when their rendered ids differ", () => { const declared = [ apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a_refreshed", "custom", "custom_a"), ]; const created = [apiKeyMethod("custom_a", "custom", "custom_a")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a_refreshed"]); }); it("returns the declared list unchanged when nothing was created", () => { const declared = [apiKeyMethod("spec-1", "spec")]; expect(mergeCustomMethods(declared, [])).toEqual(declared); }); }); describe("createCredentialPayloadOrigin", () => { it("creates an empty-string sentinel value for no-auth connection methods", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [], values: {}, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "" } }); }); it("keeps pasted credential values trimmed and keyed by input variable", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [{ variable: "token", label: "Authorization" }], values: { token: " secret-token " }, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "secret-token" } }); }); it("creates a 1Password external origin for single-input methods", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [{ variable: "token", label: "Authorization" }], values: {}, onePasswordItemId: " op://Private/Vercel/token ", singleInput: true, }), ).toEqual({ from: { provider: ProviderKey.make("onepassword"), id: ProviderItemId.make("op://Private/Vercel/token"), }, }); }); it("does not allow 1Password selection for multi-input methods yet", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [ { variable: "apiKey", label: "API key" }, { variable: "appKey", label: "Application key" }, ], values: {}, onePasswordItemId: "op://Private/Datadog/api-key", singleInput: false, }), ).toBeNull(); }); }); describe("runDcrConnect", () => { it("auto-registers (no picker) then starts: probe → register → start in order", async () => { const calls: string[] = []; let registerArgs: RegisterArgs | null = null; let startArgs: StartArgs | null = null; const probe = (_url: string): Promise => { calls.push("probe"); return Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", resource: "https://mcp.example.com/mcp", scopesSupported: ["mcp.read"], registrationEndpoint: "https://auth.example.com/register", tokenEndpointAuthMethodsSupported: ["none"], }); }; const register = (args: RegisterArgs): Promise => { calls.push("register"); registerArgs = args; return Promise.resolve(OAuthClientSlug.make("linear-mcp")); }; const start = (args: StartArgs): void => { calls.push("start"); startArgs = args; }; const outcome = await runDcrConnect( { probe, register, start }, { discoveryUrl: "https://mcp.example.com/mcp", owner: "user", integrationName: "Linear MCP", existingSlugs: [], redirectUri: "https://localhost:5394/api/oauth/callback", integration: TEST_INTEGRATION, }, ); expect(outcome.kind).toBe("started"); expect(calls).toEqual(["probe", "register", "start"]); // Registered with the probed registration endpoint + probed auth methods. // DCR always mints an authorization-code/PKCE client; callers do not choose // a grant here. expect(registerArgs).not.toBeNull(); expect(registerArgs!.registrationEndpoint).toBe("https://auth.example.com/register"); expect(registerArgs!.authorizationUrl).toBe("https://auth.example.com/authorize"); expect(registerArgs!.tokenUrl).toBe("https://auth.example.com/token"); expect(registerArgs!.resource).toBe("https://mcp.example.com/mcp"); expect(registerArgs!.tokenEndpointAuthMethodsSupported).toEqual(["none"]); expect(registerArgs!.scopes).toEqual(["mcp.read"]); expect(registerArgs!.redirectUri).toBe("https://localhost:5394/api/oauth/callback"); expect(registerArgs!.originIntegration).toBe(TEST_INTEGRATION); // Started with the minted client slug under the chosen owner. expect(startArgs).not.toBeNull(); expect(String(startArgs!.client)).toBe("linear-mcp"); expect(startArgs!.owner).toBe("user"); }); it("prefers declared scopes over probed scopes when present", async () => { let registerArgs: RegisterArgs | null = null; const outcome = await runDcrConnect( { probe: (): Promise => Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", scopesSupported: ["probed.scope"], registrationEndpoint: "https://auth.example.com/register", }), register: (args: RegisterArgs): Promise => { registerArgs = args; return Promise.resolve(OAuthClientSlug.make("app")); }, start: (): void => {}, }, { discoveryUrl: "https://mcp.example.com/mcp", owner: "user", integrationName: "App", existingSlugs: [], declaredScopes: ["declared.scope"], integration: TEST_INTEGRATION, }, ); expect(outcome.kind).toBe("started"); expect(registerArgs!.scopes).toEqual(["declared.scope"]); }); it("falls back to BYO when there is no registration endpoint (no register/start)", async () => { const calls: string[] = []; const outcome = await runDcrConnect( { probe: (): Promise => { calls.push("probe"); return Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", registrationEndpoint: null, }); }, register: (): Promise => { calls.push("register"); return Promise.resolve(OAuthClientSlug.make("app")); }, start: (): void => { calls.push("start"); }, }, { discoveryUrl: "https://mcp.example.com/mcp", owner: "user", integrationName: "App", existingSlugs: [], integration: TEST_INTEGRATION, }, ); expect(outcome).toEqual({ kind: "fallback", reason: "no-registration-endpoint", }); expect(calls).toEqual(["probe"]); }); it("falls back to BYO when the probe fails (no register/start)", async () => { const calls: string[] = []; const outcome = await runDcrConnect( { probe: (): Promise => { calls.push("probe"); return Promise.resolve(null); }, register: (): Promise => { calls.push("register"); return Promise.resolve(OAuthClientSlug.make("app")); }, start: (): void => { calls.push("start"); }, }, { discoveryUrl: "https://mcp.example.com/mcp", owner: "user", integrationName: "App", existingSlugs: [], integration: TEST_INTEGRATION, }, ); expect(outcome).toEqual({ kind: "fallback", reason: "probe-failed" }); expect(calls).toEqual(["probe"]); }); it("falls back when registration itself fails (start not called)", async () => { const calls: string[] = []; const outcome = await runDcrConnect( { probe: (): Promise => Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", registrationEndpoint: "https://auth.example.com/register", }), register: (): Promise => { calls.push("register"); return Promise.resolve(null); }, start: (): void => { calls.push("start"); }, }, { discoveryUrl: "https://mcp.example.com/mcp", owner: "user", integrationName: "App", existingSlugs: [], integration: TEST_INTEGRATION, }, ); expect(outcome.kind).toBe("fallback"); expect(calls).toEqual(["register"]); }); });