mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
test: dedupe repeated test fixtures and assertions
This commit is contained in:
@@ -5,6 +5,23 @@ import "./test-helpers/fast-coding-tools.js";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
|
||||
function createMockUsage(input: number, output: number) {
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: input + output,
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
total: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
vi.mock("@mariozechner/pi-coding-agent", async () => {
|
||||
const actual = await vi.importActual<typeof import("@mariozechner/pi-coding-agent")>(
|
||||
"@mariozechner/pi-coding-agent",
|
||||
@@ -40,20 +57,7 @@ vi.mock("@mariozechner/pi-ai", async () => {
|
||||
api: model.api,
|
||||
provider: model.provider,
|
||||
model: model.id,
|
||||
usage: {
|
||||
input: 1,
|
||||
output: 1,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 2,
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
total: 0,
|
||||
},
|
||||
},
|
||||
usage: createMockUsage(1, 1),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
@@ -65,20 +69,7 @@ vi.mock("@mariozechner/pi-ai", async () => {
|
||||
api: model.api,
|
||||
provider: model.provider,
|
||||
model: model.id,
|
||||
usage: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 0,
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
total: 0,
|
||||
},
|
||||
},
|
||||
usage: createMockUsage(0, 0),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
@@ -314,20 +305,7 @@ describe.concurrent("runEmbeddedPiAgent", () => {
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
model: "mock-1",
|
||||
usage: {
|
||||
input: 1,
|
||||
output: 1,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 2,
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
total: 0,
|
||||
},
|
||||
},
|
||||
usage: createMockUsage(1, 1),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,32 @@ import { createAssistantMessageEventStream } from "@mariozechner/pi-ai";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyExtraParamsToAgent } from "./extra-params.js";
|
||||
|
||||
type StreamPayload = {
|
||||
messages: Array<{
|
||||
role: string;
|
||||
content: unknown;
|
||||
}>;
|
||||
};
|
||||
|
||||
function runOpenRouterPayload(payload: StreamPayload, modelId: string) {
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
options?.onPayload?.(payload);
|
||||
return createAssistantMessageEventStream();
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", modelId);
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: modelId,
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
|
||||
void agent.streamFn?.(model, context, {});
|
||||
}
|
||||
|
||||
describe("extra-params: OpenRouter Anthropic cache_control", () => {
|
||||
it("injects cache_control into system message for OpenRouter Anthropic models", () => {
|
||||
const payload = {
|
||||
@@ -12,22 +38,8 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
|
||||
{ role: "user", content: "Hello" },
|
||||
],
|
||||
};
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
options?.onPayload?.(payload);
|
||||
return createAssistantMessageEventStream();
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", "anthropic/claude-opus-4-6");
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: "anthropic/claude-opus-4-6",
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
|
||||
void agent.streamFn?.(model, context, {});
|
||||
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
|
||||
|
||||
expect(payload.messages[0].content).toEqual([
|
||||
{ type: "text", text: "You are a helpful assistant.", cache_control: { type: "ephemeral" } },
|
||||
@@ -47,22 +59,8 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
options?.onPayload?.(payload);
|
||||
return createAssistantMessageEventStream();
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", "anthropic/claude-opus-4-6");
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: "anthropic/claude-opus-4-6",
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
|
||||
void agent.streamFn?.(model, context, {});
|
||||
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
|
||||
|
||||
const content = payload.messages[0].content as Array<Record<string, unknown>>;
|
||||
expect(content[0]).toEqual({ type: "text", text: "Part 1" });
|
||||
@@ -77,23 +75,19 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
|
||||
const payload = {
|
||||
messages: [{ role: "system", content: "You are a helpful assistant." }],
|
||||
};
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
options?.onPayload?.(payload);
|
||||
return createAssistantMessageEventStream();
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", "google/gemini-3-pro");
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: "google/gemini-3-pro",
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
|
||||
void agent.streamFn?.(model, context, {});
|
||||
runOpenRouterPayload(payload, "google/gemini-3-pro");
|
||||
|
||||
expect(payload.messages[0].content).toBe("You are a helpful assistant.");
|
||||
});
|
||||
|
||||
it("leaves payload unchanged when no system message exists", () => {
|
||||
const payload = {
|
||||
messages: [{ role: "user", content: "Hello" }],
|
||||
};
|
||||
|
||||
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
|
||||
|
||||
expect(payload.messages[0].content).toBe("Hello");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,6 +35,23 @@ function buildResolvedConfig(): ResolvedBrowserConfig {
|
||||
describe("startBrowserBridgeServer auth", () => {
|
||||
const servers: Array<{ stop: () => Promise<void> }> = [];
|
||||
|
||||
async function expectAuthFlow(
|
||||
authConfig: { authToken?: string; authPassword?: string },
|
||||
headers: Record<string, string>,
|
||||
) {
|
||||
const bridge = await startBrowserBridgeServer({
|
||||
resolved: buildResolvedConfig(),
|
||||
...authConfig,
|
||||
});
|
||||
servers.push({ stop: () => stopBrowserBridgeServer(bridge.server) });
|
||||
|
||||
const unauth = await fetch(`${bridge.baseUrl}/`);
|
||||
expect(unauth.status).toBe(401);
|
||||
|
||||
const authed = await fetch(`${bridge.baseUrl}/`, { headers });
|
||||
expect(authed.status).toBe(200);
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
while (servers.length) {
|
||||
const s = servers.pop();
|
||||
@@ -45,35 +62,14 @@ describe("startBrowserBridgeServer auth", () => {
|
||||
});
|
||||
|
||||
it("rejects unauthenticated requests when authToken is set", async () => {
|
||||
const bridge = await startBrowserBridgeServer({
|
||||
resolved: buildResolvedConfig(),
|
||||
authToken: "secret-token",
|
||||
});
|
||||
servers.push({ stop: () => stopBrowserBridgeServer(bridge.server) });
|
||||
|
||||
const unauth = await fetch(`${bridge.baseUrl}/`);
|
||||
expect(unauth.status).toBe(401);
|
||||
|
||||
const authed = await fetch(`${bridge.baseUrl}/`, {
|
||||
headers: { Authorization: "Bearer secret-token" },
|
||||
});
|
||||
expect(authed.status).toBe(200);
|
||||
await expectAuthFlow({ authToken: "secret-token" }, { Authorization: "Bearer secret-token" });
|
||||
});
|
||||
|
||||
it("accepts x-openclaw-password when authPassword is set", async () => {
|
||||
const bridge = await startBrowserBridgeServer({
|
||||
resolved: buildResolvedConfig(),
|
||||
authPassword: "secret-password",
|
||||
});
|
||||
servers.push({ stop: () => stopBrowserBridgeServer(bridge.server) });
|
||||
|
||||
const unauth = await fetch(`${bridge.baseUrl}/`);
|
||||
expect(unauth.status).toBe(401);
|
||||
|
||||
const authed = await fetch(`${bridge.baseUrl}/`, {
|
||||
headers: { "x-openclaw-password": "secret-password" },
|
||||
});
|
||||
expect(authed.status).toBe(200);
|
||||
await expectAuthFlow(
|
||||
{ authPassword: "secret-password" },
|
||||
{ "x-openclaw-password": "secret-password" },
|
||||
);
|
||||
});
|
||||
|
||||
it("requires auth params", async () => {
|
||||
|
||||
@@ -17,33 +17,42 @@ import { execFileSync } from "node:child_process";
|
||||
import * as fs from "node:fs";
|
||||
|
||||
describe("browser default executable detection", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
const launchServicesPlist = "com.apple.launchservices.secure.plist";
|
||||
const chromeExecutablePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
||||
|
||||
it("prefers default Chromium browser on macOS", () => {
|
||||
function mockMacDefaultBrowser(bundleId: string, appPath = ""): void {
|
||||
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
||||
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
||||
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
||||
return JSON.stringify([
|
||||
{ LSHandlerURLScheme: "http", LSHandlerRoleAll: "com.google.Chrome" },
|
||||
]);
|
||||
return JSON.stringify([{ LSHandlerURLScheme: "http", LSHandlerRoleAll: bundleId }]);
|
||||
}
|
||||
if (cmd === "/usr/bin/osascript" && argsStr.includes("path to application id")) {
|
||||
return "/Applications/Google Chrome.app";
|
||||
return appPath;
|
||||
}
|
||||
if (cmd === "/usr/bin/defaults") {
|
||||
return "Google Chrome";
|
||||
}
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
function mockChromeExecutableExists(): void {
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
||||
const value = String(p);
|
||||
if (value.includes("com.apple.launchservices.secure.plist")) {
|
||||
if (value.includes(launchServicesPlist)) {
|
||||
return true;
|
||||
}
|
||||
return value.includes("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
|
||||
return value.includes(chromeExecutablePath);
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("prefers default Chromium browser on macOS", () => {
|
||||
mockMacDefaultBrowser("com.google.Chrome", "/Applications/Google Chrome.app");
|
||||
mockChromeExecutableExists();
|
||||
|
||||
const exe = resolveBrowserExecutableForPlatform(
|
||||
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
|
||||
@@ -55,22 +64,8 @@ describe("browser default executable detection", () => {
|
||||
});
|
||||
|
||||
it("falls back when default browser is non-Chromium on macOS", () => {
|
||||
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
||||
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
||||
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
||||
return JSON.stringify([
|
||||
{ LSHandlerURLScheme: "http", LSHandlerRoleAll: "com.apple.Safari" },
|
||||
]);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
||||
const value = String(p);
|
||||
if (value.includes("com.apple.launchservices.secure.plist")) {
|
||||
return true;
|
||||
}
|
||||
return value.includes("Google Chrome.app/Contents/MacOS/Google Chrome");
|
||||
});
|
||||
mockMacDefaultBrowser("com.apple.Safari");
|
||||
mockChromeExecutableExists();
|
||||
|
||||
const exe = resolveBrowserExecutableForPlatform(
|
||||
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
|
||||
|
||||
@@ -22,6 +22,15 @@ async function readJson(filePath: string): Promise<Record<string, unknown>> {
|
||||
return JSON.parse(raw) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
async function readDefaultProfileFromLocalState(
|
||||
userDataDir: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
const localState = await readJson(path.join(userDataDir, "Local State"));
|
||||
const profile = localState.profile as Record<string, unknown>;
|
||||
const infoCache = profile.info_cache as Record<string, unknown>;
|
||||
return infoCache.Default as Record<string, unknown>;
|
||||
}
|
||||
|
||||
describe("browser chrome profile decoration", () => {
|
||||
let fixtureRoot = "";
|
||||
let fixtureCount = 0;
|
||||
@@ -53,10 +62,7 @@ describe("browser chrome profile decoration", () => {
|
||||
|
||||
const expectedSignedArgb = ((0xff << 24) | 0xff4500) >> 0;
|
||||
|
||||
const localState = await readJson(path.join(userDataDir, "Local State"));
|
||||
const profile = localState.profile as Record<string, unknown>;
|
||||
const infoCache = profile.info_cache as Record<string, unknown>;
|
||||
const def = infoCache.Default as Record<string, unknown>;
|
||||
const def = await readDefaultProfileFromLocalState(userDataDir);
|
||||
|
||||
expect(def.name).toBe(DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME);
|
||||
expect(def.shortcut_name).toBe(DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME);
|
||||
@@ -84,10 +90,7 @@ describe("browser chrome profile decoration", () => {
|
||||
it("best-effort writes name when color is invalid", async () => {
|
||||
const userDataDir = await createUserDataDir();
|
||||
decorateOpenClawProfile(userDataDir, { color: "lobster-orange" });
|
||||
const localState = await readJson(path.join(userDataDir, "Local State"));
|
||||
const profile = localState.profile as Record<string, unknown>;
|
||||
const infoCache = profile.info_cache as Record<string, unknown>;
|
||||
const def = infoCache.Default as Record<string, unknown>;
|
||||
const def = await readDefaultProfileFromLocalState(userDataDir);
|
||||
|
||||
expect(def.name).toBe(DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME);
|
||||
expect(def.profile_color_seed).toBeUndefined();
|
||||
|
||||
@@ -14,6 +14,7 @@ import type { TelegramProbe } from "../../telegram/probe.js";
|
||||
import type { TelegramTokenResolution } from "../../telegram/token.js";
|
||||
import {
|
||||
createChannelTestPluginBase,
|
||||
createMSTeamsTestPluginBase,
|
||||
createOutboundTestPlugin,
|
||||
createTestRegistry,
|
||||
} from "../../test-utils/channel-plugins.js";
|
||||
@@ -131,20 +132,7 @@ const msteamsOutbound: ChannelOutboundAdapter = {
|
||||
};
|
||||
|
||||
const msteamsPlugin: ChannelPlugin = {
|
||||
id: "msteams",
|
||||
meta: {
|
||||
id: "msteams",
|
||||
label: "Microsoft Teams",
|
||||
selectionLabel: "Microsoft Teams (Bot Framework)",
|
||||
docsPath: "/channels/msteams",
|
||||
blurb: "Bot Framework; enterprise support.",
|
||||
aliases: ["teams"],
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"] },
|
||||
config: {
|
||||
listAccountIds: () => [],
|
||||
resolveAccount: () => ({}),
|
||||
},
|
||||
...createMSTeamsTestPluginBase(),
|
||||
outbound: msteamsOutbound,
|
||||
};
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ vi.mock("../imessage/send.js", () => {
|
||||
});
|
||||
|
||||
describe("createDefaultDeps", () => {
|
||||
function expectUnusedModulesNotLoaded(exclude: keyof typeof moduleLoads): void {
|
||||
const keys = Object.keys(moduleLoads) as Array<keyof typeof moduleLoads>;
|
||||
for (const key of keys) {
|
||||
if (key === exclude) {
|
||||
continue;
|
||||
}
|
||||
expect(moduleLoads[key]).not.toHaveBeenCalled();
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
@@ -71,11 +81,7 @@ describe("createDefaultDeps", () => {
|
||||
|
||||
expect(moduleLoads.telegram).toHaveBeenCalledTimes(1);
|
||||
expect(sendFns.telegram).toHaveBeenCalledTimes(1);
|
||||
expect(moduleLoads.whatsapp).not.toHaveBeenCalled();
|
||||
expect(moduleLoads.discord).not.toHaveBeenCalled();
|
||||
expect(moduleLoads.slack).not.toHaveBeenCalled();
|
||||
expect(moduleLoads.signal).not.toHaveBeenCalled();
|
||||
expect(moduleLoads.imessage).not.toHaveBeenCalled();
|
||||
expectUnusedModulesNotLoaded("telegram");
|
||||
});
|
||||
|
||||
it("reuses module cache after first dynamic import", async () => {
|
||||
|
||||
@@ -104,6 +104,17 @@ function makeRuntime() {
|
||||
};
|
||||
}
|
||||
|
||||
function expectModelRegistryUnavailable(
|
||||
runtime: ReturnType<typeof makeRuntime>,
|
||||
expectedDetail: string,
|
||||
) {
|
||||
expect(runtime.error).toHaveBeenCalledTimes(1);
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain("Model registry unavailable:");
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain(expectedDetail);
|
||||
expect(runtime.log).not.toHaveBeenCalled();
|
||||
expect(process.exitCode).toBe(1);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
previousExitCode = process.exitCode;
|
||||
process.exitCode = undefined;
|
||||
@@ -432,12 +443,8 @@ describe("models list/status", () => {
|
||||
const runtime = makeRuntime();
|
||||
await modelsListCommand({ json: true }, runtime);
|
||||
|
||||
expect(runtime.error).toHaveBeenCalledTimes(1);
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain("Model registry unavailable:");
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain("model discovery failed");
|
||||
expectModelRegistryUnavailable(runtime, "model discovery failed");
|
||||
expect(runtime.error.mock.calls[0]?.[0]).not.toContain("configured models may appear missing");
|
||||
expect(runtime.log).not.toHaveBeenCalled();
|
||||
expect(process.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("models list fails fast when registry model discovery is unavailable", async () => {
|
||||
@@ -452,11 +459,7 @@ describe("models list/status", () => {
|
||||
modelRegistryState.available = [];
|
||||
await modelsListCommand({ json: true }, runtime);
|
||||
|
||||
expect(runtime.error).toHaveBeenCalledTimes(1);
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain("Model registry unavailable:");
|
||||
expect(runtime.error.mock.calls[0]?.[0]).toContain("model discovery unavailable");
|
||||
expect(runtime.log).not.toHaveBeenCalled();
|
||||
expect(process.exitCode).toBe(1);
|
||||
expectModelRegistryUnavailable(runtime, "model discovery unavailable");
|
||||
});
|
||||
|
||||
it("loadModelRegistry throws when model discovery is unavailable", async () => {
|
||||
|
||||
@@ -51,6 +51,27 @@ export const createChannelTestPluginBase = (params: {
|
||||
},
|
||||
});
|
||||
|
||||
export const createMSTeamsTestPluginBase = (): Pick<
|
||||
ChannelPlugin,
|
||||
"id" | "meta" | "capabilities" | "config"
|
||||
> => {
|
||||
const base = createChannelTestPluginBase({
|
||||
id: "msteams",
|
||||
label: "Microsoft Teams",
|
||||
docsPath: "/channels/msteams",
|
||||
config: { listAccountIds: () => [], resolveAccount: () => ({}) },
|
||||
});
|
||||
return {
|
||||
...base,
|
||||
meta: {
|
||||
...base.meta,
|
||||
selectionLabel: "Microsoft Teams (Bot Framework)",
|
||||
blurb: "Bot Framework; enterprise support.",
|
||||
aliases: ["teams"],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const createOutboundTestPlugin = (params: {
|
||||
id: ChannelId;
|
||||
outbound: ChannelOutboundAdapter;
|
||||
|
||||
@@ -1,43 +1,13 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import type { PluginRegistry } from "../plugins/registry.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { createMSTeamsTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
|
||||
import { resolveGatewayMessageChannel } from "./message-channel.js";
|
||||
|
||||
const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({
|
||||
plugins: [],
|
||||
tools: [],
|
||||
hooks: [],
|
||||
typedHooks: [],
|
||||
channels,
|
||||
commands: [],
|
||||
providers: [],
|
||||
gatewayHandlers: {},
|
||||
httpHandlers: [],
|
||||
httpRoutes: [],
|
||||
cliRegistrars: [],
|
||||
services: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
const emptyRegistry = createRegistry([]);
|
||||
|
||||
const msteamsPlugin = {
|
||||
id: "msteams",
|
||||
meta: {
|
||||
id: "msteams",
|
||||
label: "Microsoft Teams",
|
||||
selectionLabel: "Microsoft Teams (Bot Framework)",
|
||||
docsPath: "/channels/msteams",
|
||||
blurb: "Bot Framework; enterprise support.",
|
||||
aliases: ["teams"],
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"] },
|
||||
config: {
|
||||
listAccountIds: () => [],
|
||||
resolveAccount: () => ({}),
|
||||
},
|
||||
} satisfies ChannelPlugin;
|
||||
const emptyRegistry = createTestRegistry([]);
|
||||
const msteamsPlugin: ChannelPlugin = {
|
||||
...createMSTeamsTestPluginBase(),
|
||||
};
|
||||
|
||||
describe("message-channel", () => {
|
||||
beforeEach(() => {
|
||||
@@ -57,7 +27,7 @@ describe("message-channel", () => {
|
||||
|
||||
it("normalizes plugin aliases when registered", () => {
|
||||
setActivePluginRegistry(
|
||||
createRegistry([{ pluginId: "msteams", plugin: msteamsPlugin, source: "test" }]),
|
||||
createTestRegistry([{ pluginId: "msteams", plugin: msteamsPlugin, source: "test" }]),
|
||||
);
|
||||
expect(resolveGatewayMessageChannel("teams")).toBe("msteams");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user