Files
openclaw/extensions/mattermost/src/setup.test.ts
2026-03-25 04:25:02 +00:00

302 lines
8.7 KiB
TypeScript

import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createTestPluginApi } from "../../../test/helpers/extensions/plugin-api.js";
import plugin from "../index.js";
import type { OpenClawConfig, OpenClawPluginApi } from "../runtime-api.js";
import { mattermostSetupWizard } from "./setup-surface.js";
const resolveMattermostAccount = vi.hoisted(() => vi.fn());
const normalizeMattermostBaseUrl = vi.hoisted(() => vi.fn((value: string | undefined) => value));
const hasConfiguredSecretInput = vi.hoisted(() => vi.fn((value: unknown) => Boolean(value)));
vi.mock("./mattermost/accounts.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./mattermost/accounts.js")>();
return {
...actual,
resolveMattermostAccount: (...args: Parameters<typeof actual.resolveMattermostAccount>) => {
const mocked = resolveMattermostAccount(...args);
return mocked === undefined ? actual.resolveMattermostAccount(...args) : mocked;
},
};
});
vi.mock("./mattermost/client.js", () => ({
normalizeMattermostBaseUrl,
}));
vi.mock("./secret-input.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./secret-input.js")>();
return {
...actual,
hasConfiguredSecretInput,
};
});
function createApi(
registrationMode: OpenClawPluginApi["registrationMode"],
registerHttpRoute = vi.fn(),
): OpenClawPluginApi {
return createTestPluginApi({
id: "mattermost",
name: "Mattermost",
source: "test",
config: {},
runtime: {} as OpenClawPluginApi["runtime"],
registrationMode,
registerHttpRoute,
});
}
describe("mattermost setup", () => {
afterEach(() => {
resolveMattermostAccount.mockReset();
normalizeMattermostBaseUrl.mockReset();
normalizeMattermostBaseUrl.mockImplementation((value: string | undefined) => value);
hasConfiguredSecretInput.mockReset();
hasConfiguredSecretInput.mockImplementation((value: unknown) => Boolean(value));
vi.unstubAllEnvs();
});
it("reports configuration only when token and base url are both present", async () => {
const { isMattermostConfigured } = await import("./setup-core.js");
expect(
isMattermostConfigured({
botToken: "bot-token",
baseUrl: "https://chat.example.com",
config: {},
} as never),
).toBe(true);
expect(
isMattermostConfigured({
botToken: "",
baseUrl: "https://chat.example.com",
config: { botToken: "secret-ref" },
} as never),
).toBe(true);
expect(
isMattermostConfigured({
botToken: "",
baseUrl: "",
config: {},
} as never),
).toBe(false);
});
it("resolves accounts with unresolved secret refs allowed", async () => {
resolveMattermostAccount.mockReturnValue({ accountId: "default" });
const { resolveMattermostAccountWithSecrets } = await import("./setup-core.js");
const cfg = { channels: { mattermost: {} } };
expect(resolveMattermostAccountWithSecrets(cfg as never, "default")).toEqual({
accountId: "default",
});
expect(resolveMattermostAccount).toHaveBeenCalledWith({
cfg,
accountId: "default",
allowUnresolvedSecretRef: true,
});
});
it("validates env and explicit credential requirements", async () => {
const { mattermostSetupAdapter } = await import("./setup-core.js");
const validateInput = mattermostSetupAdapter.validateInput;
expect(validateInput).toBeTypeOf("function");
expect(
validateInput!({
accountId: "secondary",
input: { useEnv: true },
} as never),
).toBe("Mattermost env vars can only be used for the default account.");
normalizeMattermostBaseUrl.mockReturnValue(undefined);
expect(
validateInput!({
accountId: DEFAULT_ACCOUNT_ID,
input: { useEnv: false, botToken: "tok", httpUrl: "not-a-url" },
} as never),
).toBe("Mattermost requires --bot-token and --http-url (or --use-env).");
normalizeMattermostBaseUrl.mockReturnValue("https://chat.example.com");
expect(
validateInput!({
accountId: DEFAULT_ACCOUNT_ID,
input: { useEnv: false, botToken: "tok", httpUrl: "https://chat.example.com" },
} as never),
).toBeNull();
});
it("applies normalized config for default and named accounts", async () => {
normalizeMattermostBaseUrl.mockReturnValue("https://chat.example.com");
const { mattermostSetupAdapter } = await import("./setup-core.js");
const applyAccountConfig = mattermostSetupAdapter.applyAccountConfig;
expect(applyAccountConfig).toBeTypeOf("function");
expect(
applyAccountConfig!({
cfg: { channels: { mattermost: {} } },
accountId: DEFAULT_ACCOUNT_ID,
input: {
name: "Default",
botToken: "tok",
httpUrl: "https://chat.example.com",
},
} as never),
).toEqual({
channels: {
mattermost: {
enabled: true,
name: "Default",
botToken: "tok",
baseUrl: "https://chat.example.com",
},
},
});
expect(
applyAccountConfig!({
cfg: {
channels: {
mattermost: {
name: "Legacy",
},
},
},
accountId: "Work Team",
input: {
name: "Work",
botToken: "tok2",
httpUrl: "https://chat.example.com",
},
} as never),
).toMatchObject({
channels: {
mattermost: {
accounts: {
default: { name: "Legacy" },
"work-team": {
enabled: true,
name: "Work",
botToken: "tok2",
baseUrl: "https://chat.example.com",
},
},
},
},
});
});
it("skips slash callback registration in setup-only mode", () => {
const registerHttpRoute = vi.fn();
plugin.register(createApi("setup-only", registerHttpRoute));
expect(registerHttpRoute).not.toHaveBeenCalled();
});
it("registers slash callback routes in full mode", () => {
const registerHttpRoute = vi.fn();
plugin.register(createApi("full", registerHttpRoute));
expect(registerHttpRoute).toHaveBeenCalledTimes(1);
expect(registerHttpRoute).toHaveBeenCalledWith(
expect.objectContaining({
path: "/api/channels/mattermost/command",
auth: "plugin",
}),
);
});
it.each(["https://chat.example.com", "https://chat.example.test"])(
"treats secret-ref tokens plus base url as configured: %s",
async (baseUrl) => {
const configured = await mattermostSetupWizard.status.resolveConfigured({
cfg: {
channels: {
mattermost: {
baseUrl,
botToken: {
source: "env",
provider: "default",
id: "MATTERMOST_BOT_TOKEN",
},
},
},
} as OpenClawConfig,
});
expect(configured).toBe(true);
},
);
it("shows intro note only when the target account is not configured", () => {
expect(
mattermostSetupWizard.introNote?.shouldShow?.({
cfg: {
channels: {
mattermost: {},
},
} as OpenClawConfig,
accountId: "default",
} as never),
).toBe(true);
expect(
mattermostSetupWizard.introNote?.shouldShow?.({
cfg: {
channels: {
mattermost: {
baseUrl: "https://chat.example.com",
botToken: {
source: "env",
provider: "default",
id: "MATTERMOST_BOT_TOKEN",
},
},
},
} as OpenClawConfig,
accountId: "default",
} as never),
).toBe(false);
});
it("offers env shortcut only for the default account when env is present and config is empty", () => {
vi.stubEnv("MATTERMOST_BOT_TOKEN", "bot-token");
vi.stubEnv("MATTERMOST_URL", "https://chat.example.com");
expect(
mattermostSetupWizard.envShortcut?.isAvailable?.({
cfg: { channels: { mattermost: {} } } as OpenClawConfig,
accountId: "default",
} as never),
).toBe(true);
expect(
mattermostSetupWizard.envShortcut?.isAvailable?.({
cfg: { channels: { mattermost: {} } } as OpenClawConfig,
accountId: "work",
} as never),
).toBe(false);
});
it("keeps env shortcut as a no-op patch for the selected account", () => {
expect(
mattermostSetupWizard.envShortcut?.apply?.({
cfg: { channels: { mattermost: { enabled: false } } } as OpenClawConfig,
accountId: "default",
} as never),
).toEqual({
channels: {
mattermost: {
enabled: true,
},
},
});
});
});