import { beforeEach, describe, expect, test } from "bun:test"; import { setConfig } from "../../../__tests__/helpers/set-config.js"; import type { ExternalConversationBinding } from "../../../persistence/external-conversation-store.js"; // Seed the Slack workspace identity that the deep-link builders read. Empty // `teamId`/`teamUrl` (the schema defaults) stand in for installs that never // learned their workspace identity. function seedSlack( overrides: { teamId?: string; teamUrl?: string } = {}, ): void { setConfig("slack", { teamId: "T0EXAMPLE", teamUrl: "https://example-workspace.slack.com", ...overrides, }); } const { buildSlackBindingMetadata } = await import("./binding-metadata.js"); function makeBinding( overrides: Partial, ): ExternalConversationBinding { return { sourceChannel: "slack", externalChatId: "C0CHANNEL", externalUserId: null, displayName: null, username: null, ...overrides, } as ExternalConversationBinding; } describe("buildSlackBindingMetadata sourceLink", () => { beforeEach(() => { seedSlack(); }); test("prefers the bound thread's deep link", () => { const metadata = buildSlackBindingMetadata( makeBinding({ externalThreadId: "1720000000.000100" }), ); expect(metadata.sourceLink).toBeDefined(); expect(metadata.sourceLink).toEqual(metadata.slackThread?.link); expect(metadata.sourceLink?.webUrl).toContain("p1720000000000100"); }); test("falls back to the channel web link when no thread is bound", () => { const metadata = buildSlackBindingMetadata(makeBinding({})); expect(metadata.slackThread).toBeUndefined(); expect(metadata.sourceLink).toEqual({ webUrl: "https://example-workspace.slack.com/archives/C0CHANNEL", }); }); test("falls back to workspace-agnostic slack.com links without a teamUrl", () => { // An empty teamUrl is the schema default — e.g. installs whose Slack // connection came through the gateway and never ran the local bot-token // setup. Links must still be produced via the slack.com permalink form. seedSlack({ teamId: "", teamUrl: "" }); const metadata = buildSlackBindingMetadata(makeBinding({})); expect(metadata.sourceLink).toEqual({ webUrl: "https://slack.com/archives/C0CHANNEL", }); expect(metadata.slackChannel?.link).toEqual({ webUrl: "https://slack.com/archives/C0CHANNEL", }); }); test("thread link falls back to the slack.com permalink without a teamUrl", () => { seedSlack({ teamId: "", teamUrl: "" }); const metadata = buildSlackBindingMetadata( makeBinding({ externalThreadId: "1720000000.000100" }), ); expect(metadata.slackThread?.link).toEqual({ webUrl: "https://slack.com/archives/C0CHANNEL/p1720000000000100", }); expect(metadata.sourceLink).toEqual(metadata.slackThread?.link); }); test("keeps the slack:// app link when only the teamUrl is missing", () => { seedSlack({ teamUrl: "" }); const metadata = buildSlackBindingMetadata( makeBinding({ externalThreadId: "1720000000.000100" }), ); expect(metadata.slackThread?.link).toEqual({ appUrl: "slack://channel?team=T0EXAMPLE&id=C0CHANNEL&message=1720000000.000100", webUrl: "https://slack.com/archives/C0CHANNEL/p1720000000000100", }); }); });