Files
PaperClipAI/packages/shared/src/slack-app-manifest.test.ts
T
DottaandPaperclip 1e0cfcb4fc test: retire redundant suites and consolidate owner coverage (#15978)
Retire duplicate ACPX and Codex proof after migrating unique assertions to their behavioral owners. Consolidate repeated fixtures and exact case matrices while preserving lifecycle, protocol, company, credential, approval, and ordering contracts. Remove the unused runtime-controls compatibility path and document test ownership and preservation evidence.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-12 10:44:02 -05:00

51 lines
4.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildSlackAppManifest, defaultSlackAppConfiguration, slackRegistrationSchema, slackAccountStateSchema } from "./slack-app-manifest.js";
import { createChatEndpointSchema, slackAppConfigurationSchema } from "./validators/chat-channels.js";
describe("Slack app manifest", () => {
it("preserves older account setup state and validates optional verification delivery state", () => {
const account = { externalUserId: "UINSTALLER", paperclipUserId: "board-user", status: "linked", welcomeStatus: "sent" };
expect(slackAccountStateSchema.safeParse(account).success).toBe(true);
for (const verificationStatus of ["pending", "sending", "sent", "failed", "uncertain"]) {
expect(slackAccountStateSchema.safeParse({ ...account, verificationStatus }).success).toBe(true);
}
expect(slackAccountStateSchema.safeParse({ ...account, verificationStatus: "delivered" }).success).toBe(false);
});
it("uses readable, valid agent defaults and accepts them atomically with a new Slack draft", () => {
expect(defaultSlackAppConfiguration("Maya")).toEqual({ appName: "maya-paperclip", botName: "maya", command: "/maya" });
for (const name of ["Research Lead", "Áda Lovelace", "A.B_C", "", "Very long agent name that needs truncating"]) {
expect(slackAppConfigurationSchema.safeParse(defaultSlackAppConfiguration(name)).success).toBe(true);
}
const request = { provider: "slack", assignedAgentId: "12345678-1234-4123-8123-123456789abc", slackApp: defaultSlackAppConfiguration("Maya") };
expect(createChatEndpointSchema.safeParse(request).success).toBe(true);
expect(createChatEndpointSchema.safeParse({ ...request, provider: "discord" }).success).toBe(false);
});
const input = { app: { appName: 'Research "Ops"', botName: "research-ops", command: "/research" }, agentName: "Maya", webhookUrl: "https://ingress.example/api/chat-webhooks/public/slack" };
it("uses identical manual and automatic configuration except the OAuth redirect", () => {
const manual = buildSlackAppManifest(input);
const automatic = buildSlackAppManifest({ ...input, redirectUri: "https://board.example/api/chat-slack/oauth/callback" });
expect(automatic).toEqual({ ...manual, oauth_config: { ...manual.oauth_config, redirect_urls: ["https://board.example/api/chat-slack/oauth/callback"] } });
expect(manual.features.bot_user.display_name).toBe("research-ops");
expect(manual.features.slash_commands[0]).toMatchObject({ command: "/research", url: input.webhookUrl, should_escape: false });
expect(manual.settings.event_subscriptions.request_url).toBe(input.webhookUrl);
expect(manual.settings.interactivity).toEqual({ is_enabled: true, request_url: input.webhookUrl });
expect(manual.settings.socket_mode_enabled).toBe(false);
expect(manual.features).toHaveProperty("agent_view");
expect(manual.features).not.toHaveProperty("assistant_view");
expect(manual.features.bot_user).not.toHaveProperty("always_online");
expect(manual.features.app_home).toEqual({
home_tab_enabled: false, messages_tab_enabled: true, messages_tab_read_only_enabled: false,
});
// The reviewed provider permissions/events stay pinned across both creation paths.
expect(manual.oauth_config.scopes.bot).toMatchSnapshot();
expect(manual.settings.event_subscriptions.bot_events).toMatchSnapshot();
});
it("rejects arbitrary manifests, scopes, callback destinations, and refresh tokens", () => {
const request = { requestId: "12345678-1234-4123-8123-123456789abc", credentials: { configurationToken: "temporary" } };
expect(slackRegistrationSchema.safeParse(request).success).toBe(true);
for (const key of ["manifest", "scopes", "callbackUri", "configurationRefreshToken", "avatarUrl"])
expect(slackRegistrationSchema.safeParse({ ...request, [key]: "untrusted" }).success).toBe(false);
expect(slackRegistrationSchema.safeParse({ ...request, credentials: { ...request.credentials, refreshToken: "untrusted" } }).success).toBe(false);
});
});