Tests: share agents bind command harness

This commit is contained in:
Gustavo Madeira Santana
2026-03-28 02:09:27 -04:00
parent 5292622fec
commit d042543539
4 changed files with 120 additions and 78 deletions

View File

@@ -1,48 +1,43 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { baseConfigSnapshot, createTestRuntime } from "./test-runtime-config-helpers.js";
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
const writeConfigFileMock = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
vi.mock("../config/config.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../config/config.js")>()),
readConfigFileSnapshot: readConfigFileSnapshotMock,
writeConfigFile: writeConfigFileMock,
}));
import { createBindingResolverTestPlugin } from "../test-utils/channel-plugins.js";
import {
loadFreshAgentsCommandModuleForTest,
readConfigFileSnapshotMock,
resetAgentsBindTestHarness,
runtime,
writeConfigFileMock,
} from "./agents.bind.test-support.js";
import { baseConfigSnapshot } from "./test-runtime-config-helpers.js";
vi.mock("../channels/plugins/index.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../channels/plugins/index.js")>();
const knownChannels = new Set(["discord", "matrix", "telegram"]);
const createPlugin = (id: "discord" | "matrix" | "telegram") => ({
id,
meta: {
id,
label: id,
selectionLabel: id,
docsPath: `/channels/${id}`,
blurb: `${id} test plugin`,
},
capabilities: {},
config: {
listAccountIds: () => [],
},
});
const knownChannels = new Map([
[
"discord",
createBindingResolverTestPlugin({ id: "discord", config: { listAccountIds: () => [] } }),
],
[
"matrix",
createBindingResolverTestPlugin({
id: "matrix",
config: { listAccountIds: () => [] },
resolveBindingAccountId: ({ agentId }) => agentId.toLowerCase(),
}),
],
[
"telegram",
createBindingResolverTestPlugin({ id: "telegram", config: { listAccountIds: () => [] } }),
],
]);
return {
...actual,
getChannelPlugin: (channel: string) => {
const normalized = channel.trim().toLowerCase();
if (!knownChannels.has(normalized)) {
return actual.getChannelPlugin(channel);
const plugin = knownChannels.get(normalized);
if (plugin) {
return plugin;
}
if (normalized === "matrix") {
return {
...createPlugin("matrix"),
setup: {
resolveBindingAccountId: ({ agentId }: { agentId: string }) => agentId.toLowerCase(),
},
};
}
return createPlugin(normalized as "discord" | "telegram");
return actual.getChannelPlugin(channel);
},
normalizeChannelId: (channel: string) => {
const normalized = channel.trim().toLowerCase();
@@ -58,18 +53,11 @@ let agentsBindCommand: typeof import("./agents.js").agentsBindCommand;
let agentsBindingsCommand: typeof import("./agents.js").agentsBindingsCommand;
let agentsUnbindCommand: typeof import("./agents.js").agentsUnbindCommand;
const runtime = createTestRuntime();
describe("agents bind/unbind commands", () => {
beforeEach(async () => {
vi.resetModules();
({ agentsBindCommand, agentsBindingsCommand, agentsUnbindCommand } =
await import("./agents.js"));
readConfigFileSnapshotMock.mockClear();
writeConfigFileMock.mockClear();
runtime.log.mockClear();
runtime.error.mockClear();
runtime.exit.mockClear();
await loadFreshAgentsCommandModuleForTest());
resetAgentsBindTestHarness();
});
it("lists all bindings by default", async () => {

View File

@@ -1,45 +1,37 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
import {
createBindingResolverTestPlugin,
createTestRegistry,
} from "../test-utils/channel-plugins.js";
import {
loadFreshAgentsCommandModuleForTest,
readConfigFileSnapshotMock,
resetAgentsBindTestHarness,
runtime,
writeConfigFileMock,
} from "./agents.bind.test-support.js";
import { setDefaultChannelPluginRegistryForTests } from "./channel-test-helpers.js";
import { baseConfigSnapshot, createTestRuntime } from "./test-runtime-config-helpers.js";
import { baseConfigSnapshot } from "./test-runtime-config-helpers.js";
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
const writeConfigFileMock = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
const matrixBindingPlugin = {
...createChannelTestPluginBase({ id: "matrix" }),
setup: {
resolveBindingAccountId: ({ accountId, agentId }: { accountId?: string; agentId?: string }) => {
const explicit = accountId?.trim();
if (explicit) {
return explicit;
}
const agent = agentId?.trim();
return agent || "default";
},
const matrixBindingPlugin = createBindingResolverTestPlugin({
id: "matrix",
resolveBindingAccountId: ({ accountId, agentId }) => {
const explicit = accountId?.trim();
if (explicit) {
return explicit;
}
const agent = agentId?.trim();
return agent || "default";
},
};
vi.mock("../config/config.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../config/config.js")>()),
readConfigFileSnapshot: readConfigFileSnapshotMock,
writeConfigFile: writeConfigFileMock,
}));
});
let agentsBindCommand: typeof import("./agents.js").agentsBindCommand;
describe("agents bind matrix integration", () => {
const runtime = createTestRuntime();
beforeEach(async () => {
vi.resetModules();
({ agentsBindCommand } = await import("./agents.js"));
readConfigFileSnapshotMock.mockClear();
writeConfigFileMock.mockClear();
runtime.log.mockClear();
runtime.error.mockClear();
runtime.exit.mockClear();
({ agentsBindCommand } = await loadFreshAgentsCommandModuleForTest());
resetAgentsBindTestHarness();
setActivePluginRegistry(
createTestRegistry([{ pluginId: "matrix", plugin: matrixBindingPlugin, source: "test" }]),

View File

@@ -0,0 +1,31 @@
import { vi } from "vitest";
import { mergeMockedModule } from "../test-utils/vitest-module-mocks.js";
import { createTestRuntime } from "./test-runtime-config-helpers.js";
export const readConfigFileSnapshotMock = vi.fn();
export const writeConfigFileMock = vi.fn().mockResolvedValue(undefined);
vi.mock("../config/config.js", async (importOriginal) => {
return await mergeMockedModule(
await importOriginal<typeof import("../config/config.js")>(),
() => ({
readConfigFileSnapshot: readConfigFileSnapshotMock,
writeConfigFile: writeConfigFileMock,
}),
);
});
export const runtime = createTestRuntime();
export async function loadFreshAgentsCommandModuleForTest() {
vi.resetModules();
return await import("./agents.js");
}
export function resetAgentsBindTestHarness(): void {
readConfigFileSnapshotMock.mockClear();
writeConfigFileMock.mockClear();
runtime.log.mockClear();
runtime.error.mockClear();
runtime.exit.mockClear();
}

View File

@@ -116,3 +116,34 @@ export const createOutboundTestPlugin = (params: {
outbound: params.outbound,
...(params.messaging ? { messaging: params.messaging } : {}),
});
export type BindingResolverTestPlugin = Pick<
ChannelPlugin,
"id" | "meta" | "capabilities" | "config"
> & {
setup?: Pick<NonNullable<ChannelPlugin["setup"]>, "resolveBindingAccountId">;
};
export const createBindingResolverTestPlugin = (params: {
id: ChannelId;
label?: string;
docsPath?: string;
capabilities?: ChannelCapabilities;
config?: Partial<ChannelPlugin["config"]>;
resolveBindingAccountId?: NonNullable<ChannelPlugin["setup"]>["resolveBindingAccountId"];
}): BindingResolverTestPlugin => ({
...createChannelTestPluginBase({
id: params.id,
label: params.label,
docsPath: params.docsPath,
capabilities: params.capabilities,
config: params.config,
}),
...(params.resolveBindingAccountId
? {
setup: {
resolveBindingAccountId: params.resolveBindingAccountId,
},
}
: {}),
});