mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 20:20:43 +00:00
310 lines
8.5 KiB
TypeScript
310 lines
8.5 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import type { ChannelRuntimeSnapshot } from "../server-channel-runtime.types.js";
|
|
import type { GatewayRequestHandlerOptions } from "./types.js";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
getRuntimeConfig: vi.fn(() => ({})),
|
|
readConfigFileSnapshot: vi.fn(),
|
|
applyPluginAutoEnable: vi.fn(),
|
|
getChannelPlugin: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../../config/config.js", () => ({
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
readConfigFileSnapshot: mocks.readConfigFileSnapshot,
|
|
}));
|
|
|
|
vi.mock("../../config/plugin-auto-enable.js", () => ({
|
|
applyPluginAutoEnable: mocks.applyPluginAutoEnable,
|
|
}));
|
|
|
|
vi.mock("../../channels/plugins/index.js", () => ({
|
|
listChannelPlugins: vi.fn(),
|
|
getChannelPlugin: mocks.getChannelPlugin,
|
|
normalizeChannelId: (value: string) => value,
|
|
}));
|
|
|
|
import { channelsHandlers } from "./channels.js";
|
|
|
|
function createOptions(
|
|
params: Record<string, unknown>,
|
|
overrides?: Partial<GatewayRequestHandlerOptions>,
|
|
): GatewayRequestHandlerOptions {
|
|
return {
|
|
req: { type: "req", id: "req-1", method: "channels.start", params },
|
|
params,
|
|
client: null,
|
|
isWebchatConnect: () => false,
|
|
respond: vi.fn(),
|
|
context: {
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
startChannel: vi.fn(),
|
|
stopChannel: vi.fn(),
|
|
markChannelLoggedOut: vi.fn(),
|
|
getRuntimeSnapshot: vi.fn(
|
|
(): ChannelRuntimeSnapshot => ({
|
|
channels: {
|
|
whatsapp: {
|
|
accountId: "default-account",
|
|
running: true,
|
|
},
|
|
},
|
|
channelAccounts: {
|
|
whatsapp: {
|
|
"default-account": {
|
|
accountId: "default-account",
|
|
running: true,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
),
|
|
},
|
|
...overrides,
|
|
} as unknown as GatewayRequestHandlerOptions;
|
|
}
|
|
|
|
describe("channelsHandlers channels.start", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.getRuntimeConfig.mockReturnValue({});
|
|
mocks.applyPluginAutoEnable.mockImplementation(({ config }) => ({ config, changes: [] }));
|
|
mocks.getChannelPlugin.mockReturnValue({
|
|
id: "whatsapp",
|
|
gateway: { startAccount: vi.fn() },
|
|
config: {
|
|
defaultAccountId: () => "default-account",
|
|
listAccountIds: () => ["default-account"],
|
|
resolveAccount: () => ({}),
|
|
},
|
|
});
|
|
});
|
|
|
|
it("resolves the default account and starts the channel runtime", async () => {
|
|
const startChannel = vi.fn();
|
|
const respond = vi.fn();
|
|
|
|
await channelsHandlers["channels.start"](
|
|
createOptions(
|
|
{ channel: "whatsapp" },
|
|
{
|
|
respond,
|
|
context: {
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
startChannel,
|
|
getRuntimeSnapshot: vi.fn(
|
|
(): ChannelRuntimeSnapshot => ({
|
|
channels: {
|
|
whatsapp: {
|
|
accountId: "default-account",
|
|
running: true,
|
|
},
|
|
},
|
|
channelAccounts: {
|
|
whatsapp: {
|
|
"default-account": {
|
|
accountId: "default-account",
|
|
running: true,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
),
|
|
} as unknown as GatewayRequestHandlerOptions["context"],
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(mocks.applyPluginAutoEnable).toHaveBeenCalledWith({
|
|
config: {},
|
|
env: process.env,
|
|
});
|
|
expect(startChannel).toHaveBeenCalledWith("whatsapp", "default-account");
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
channel: "whatsapp",
|
|
accountId: "default-account",
|
|
started: true,
|
|
},
|
|
undefined,
|
|
);
|
|
});
|
|
|
|
it("reports started=false when the channel runtime remains stopped", async () => {
|
|
const startChannel = vi.fn();
|
|
const respond = vi.fn();
|
|
|
|
await channelsHandlers["channels.start"](
|
|
createOptions(
|
|
{ channel: "whatsapp" },
|
|
{
|
|
respond,
|
|
context: {
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
startChannel,
|
|
getRuntimeSnapshot: vi.fn(
|
|
(): ChannelRuntimeSnapshot => ({
|
|
channels: {
|
|
whatsapp: {
|
|
accountId: "default-account",
|
|
running: false,
|
|
},
|
|
},
|
|
channelAccounts: {
|
|
whatsapp: {
|
|
"default-account": {
|
|
accountId: "default-account",
|
|
running: false,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
),
|
|
} as unknown as GatewayRequestHandlerOptions["context"],
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(startChannel).toHaveBeenCalledWith("whatsapp", "default-account");
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
channel: "whatsapp",
|
|
accountId: "default-account",
|
|
started: false,
|
|
},
|
|
undefined,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("channelsHandlers channels.stop", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.getRuntimeConfig.mockReturnValue({});
|
|
mocks.getChannelPlugin.mockReturnValue({
|
|
id: "whatsapp",
|
|
config: {
|
|
defaultAccountId: () => "default-account",
|
|
listAccountIds: () => ["default-account"],
|
|
resolveAccount: () => ({}),
|
|
},
|
|
});
|
|
});
|
|
|
|
it("stops a channel account without clearing auth state", async () => {
|
|
const stopChannel = vi.fn(async () => undefined);
|
|
const respond = vi.fn();
|
|
|
|
await channelsHandlers["channels.stop"](
|
|
createOptions(
|
|
{ channel: "whatsapp" },
|
|
{
|
|
respond,
|
|
context: {
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
stopChannel,
|
|
getRuntimeSnapshot: vi.fn(
|
|
(): ChannelRuntimeSnapshot => ({
|
|
channels: {},
|
|
channelAccounts: {
|
|
whatsapp: {
|
|
"default-account": {
|
|
accountId: "default-account",
|
|
running: false,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
),
|
|
} as unknown as GatewayRequestHandlerOptions["context"],
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(stopChannel).toHaveBeenCalledWith("whatsapp", "default-account");
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
channel: "whatsapp",
|
|
accountId: "default-account",
|
|
stopped: true,
|
|
},
|
|
undefined,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("channelsHandlers channels.logout", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.readConfigFileSnapshot.mockResolvedValue({
|
|
valid: true,
|
|
config: {
|
|
channels: {
|
|
whatsapp: {
|
|
token: { source: "env", provider: "default", id: "WHATSAPP_TOKEN" },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("passes the active runtime config to channel plugins", async () => {
|
|
const runtimeConfig = {
|
|
channels: {
|
|
whatsapp: {
|
|
token: "runtime-token",
|
|
},
|
|
},
|
|
};
|
|
const stopChannel = vi.fn();
|
|
const markChannelLoggedOut = vi.fn();
|
|
const logoutAccount = vi.fn(async ({ cfg }: { cfg: typeof runtimeConfig }) => {
|
|
expect(cfg.channels.whatsapp.token).toBe("runtime-token");
|
|
return { cleared: true, envToken: false, loggedOut: true };
|
|
});
|
|
const respond = vi.fn();
|
|
mocks.getRuntimeConfig.mockReturnValue(runtimeConfig);
|
|
mocks.getChannelPlugin.mockReturnValue({
|
|
id: "whatsapp",
|
|
gateway: { logoutAccount },
|
|
config: {
|
|
defaultAccountId: () => "default-account",
|
|
listAccountIds: () => ["default-account"],
|
|
resolveAccount: () => ({}),
|
|
},
|
|
});
|
|
|
|
await channelsHandlers["channels.logout"](
|
|
createOptions(
|
|
{ channel: "whatsapp" },
|
|
{
|
|
respond,
|
|
context: {
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
stopChannel,
|
|
markChannelLoggedOut,
|
|
} as unknown as GatewayRequestHandlerOptions["context"],
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(stopChannel).toHaveBeenCalledWith("whatsapp", "default-account");
|
|
expect(markChannelLoggedOut).toHaveBeenCalledWith("whatsapp", true, "default-account");
|
|
expect(logoutAccount).toHaveBeenCalledTimes(1);
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
channel: "whatsapp",
|
|
accountId: "default-account",
|
|
cleared: true,
|
|
envToken: false,
|
|
loggedOut: true,
|
|
},
|
|
undefined,
|
|
);
|
|
});
|
|
});
|