229 lines · 7.5 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest"; import {  integrationFaviconSrc,  integrationFaviconUrl,  integrationInferredUrl,  integrationLocalIconUrl,  integrationPresetIconUrl,} from "./integration-favicon"; describe("IntegrationFavicon", () => {  it("resolves favicons only through the integrations.sh logo proxy", () => {    expect(integrationFaviconUrl("https://api.github.com/graphql", 20)).toBe(      "https://integrations.sh/logo/github.com?sz=40",    );  });   it("does not request favicons for local URLs", () => {    expect(integrationFaviconUrl("http://localhost:3000/private", 20)).toBeNull();    expect(integrationFaviconUrl("http://127.0.0.1:3000/private", 20)).toBeNull();  });   it("sends only the registrable domain to the logo proxy", () => {    expect(integrationFaviconUrl("https://api.github.com/private", 20)).toBe(      "https://integrations.sh/logo/github.com?sz=40",    );  });   it("falls through to the placeholder when the proxy fails", () => {    const url = "https://api.github.com/graphql";    const primary = integrationFaviconSrc({ url, size: 20 });    expect(primary).toBe("https://integrations.sh/logo/github.com?sz=40");    expect(integrationFaviconSrc({ url, size: 20, failedSrcs: [primary ?? ""] })).toBeNull();  });   it("uses the Executor favicon for the built-in executor integration", () => {    expect(integrationLocalIconUrl("executor")).toBe("/favicon-32.png");    expect(integrationLocalIconUrl("openapi")).toBeNull();  });   it("resolves the Executor sidebar icon only when the integration id is threaded (cloud/self-host repro)", () => {    // Reconstruct the props the multiplayer shell derives for the built-in    // executor integration (EXECUTOR_INTEGRATION: kind "built-in", name "Executor", no    // displayUrl). The sidebar's IntegrationList builds icon/url exactly this way.    const slug = "executor";    const name = "Executor";    const icon = integrationPresetIconUrl({ id: slug, kind: "built-in", name, url: undefined }, []);    const url = integrationInferredUrl({ id: slug, name }) ?? undefined;     // The built-in integration matches no preset and has no inferable host, so the    // integrationId branch is the only thing that can resolve its icon.    expect(icon).toBeNull();    expect(url).toBeUndefined();     // Bug: cloud/self-host dropped integrationId, so the cascade fell through to null    // and rendered the neutral BoxIcon placeholder.    expect(integrationFaviconSrc({ icon, url, size: 16 })).toBeNull();     // Fix: threading integrationId resolves the bundled Executor favicon.    expect(integrationFaviconSrc({ icon, integrationId: slug, url, size: 16 })).toBe(      "/favicon-32.png",    );  });   it("finds preset icons from an integration URL", () => {    expect(      integrationPresetIconUrl(        {          id: "google_sheets",          kind: "googleDiscovery",          name: "Google Sheets API",          url: "https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest",        },        [          {            key: "google",            label: "Google",            add: () => null,            edit: () => null,            presets: [              {                id: "google-sheets",                name: "Google Sheets",                summary: "Spreadsheets.",                url: "https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest",                icon: "https://example.com/sheets.svg",              },            ],          },        ],      ),    ).toBe("https://example.com/sheets.svg");  });   it("does not fuzzy-match preset icons from names or slugs", () => {    // Name/slug token matching is gone: without an exact defaultSlug or URL    // match, the preset matcher declines and the cascade resolves through the    // integrations.sh favicon instead, which is derived from the integration's    // own domain and therefore cannot render the wrong brand.    const presets = [      {        key: "mcp",        label: "MCP",        add: () => null,        edit: () => null,        presets: [          {            id: "sentry",            name: "Sentry",            summary: "Errors.",            icon: "https://example.com/sentry.png",          },        ],      },    ];     expect(      integrationPresetIconUrl({ id: "sentry", kind: "mcp", name: "Sentry MCP" }, presets),    ).toBeNull();     // Migrated host-shaped integrations resolve through the inferred URL:    const inferred = integrationInferredUrl({ id: "mcp_posthog_com", name: "mcp.posthog.com" });    expect(inferred).toBe("https://mcp.posthog.com");    expect(integrationFaviconSrc({ url: inferred ?? undefined, size: 16 })).toBe(      "https://integrations.sh/logo/posthog.com?sz=32",    );  });   it("prefers exact catalog defaultSlug icons for OpenAPI provider services", () => {    expect(      integrationPresetIconUrl({ id: "google_gmail", kind: "openapi", name: "Gmail" }, [        {          key: "openapi",          label: "OpenAPI",          add: () => null,          edit: () => null,          presets: [            {              id: "google-gmail",              name: "Gmail",              summary: "Messages.",              defaultSlug: "google_gmail",              icon: "https://example.com/gmail.png",            },          ],        },      ]),    ).toBe("https://example.com/gmail.png");  });   it("matches presets on exact URL equality, not names", () => {    const presets = [      {        key: "openapi",        label: "OpenAPI",        add: () => null,        edit: () => null,        presets: [          {            id: "spotify",            name: "Spotify",            summary: "Music.",            url: "https://api.spotify.com/v1",            icon: "https://example.com/spotify.png",          },        ],      },    ];     expect(      integrationPresetIconUrl(        {          id: "spotify_web_api",          kind: "openapi",          name: "Spotify Web API",          url: "https://api.spotify.com/v1",        },        presets,      ),    ).toBe("https://example.com/spotify.png");     // Same name, different URL: no match — the URL-derived favicon takes over.    expect(      integrationPresetIconUrl(        {          id: "spotify_web_api",          kind: "openapi",          name: "Spotify Web API",          url: "https://api.spotify.com/v2",        },        presets,      ),    ).toBeNull();  });   it("does not match a different brand sharing a word fragment (ClickHouse Cloud vs Cloudflare)", () => {    expect(      integrationPresetIconUrl({ id: "clickhouse", kind: "mcp", name: "ClickHouse Cloud" }, [        {          key: "mcp",          label: "MCP",          add: () => null,          edit: () => null,          presets: [            {              id: "cloudflare",              name: "Cloudflare",              summary: "Workers, KV, D1, R2, and DNS management via MCP.",              icon: "https://integrations.sh/logo/cloudflare.com",            },          ],        },      ]),    ).toBeNull();  });   it("infers favicon URLs from migrated host-shaped MCP names and slugs", () => {    expect(integrationInferredUrl({ id: "mcp_posthog_com", name: "mcp.posthog.com" })).toBe(      "https://mcp.posthog.com",    );    expect(integrationInferredUrl({ id: "ai_todoist_net", name: "ai.todoist.net" })).toBe(      "https://ai.todoist.net",    );    expect(integrationInferredUrl({ id: "mcp_pscale_dev", name: "mcp.pscale.dev" })).toBe(      "https://mcp.pscale.dev",    );    expect(integrationInferredUrl({ id: "stripe_api", name: "Stripe API" })).toBeNull();  });});