Tests: lock plugin slash commands to one runtime graph

This commit is contained in:
Vincent Koc
2026-03-16 18:30:30 -07:00
parent 8a10903cf7
commit 6805a80da2
3 changed files with 302 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import type { NativeCommandSpec } from "../../../../src/auto-reply/commands-regi
import * as dispatcherModule from "../../../../src/auto-reply/reply/provider-dispatcher.js";
import type { OpenClawConfig } from "../../../../src/config/config.js";
import * as pluginCommandsModule from "../../../../src/plugins/commands.js";
import { clearPluginCommands, registerPluginCommand } from "../../../../src/plugins/commands.js";
import { createDiscordNativeCommand } from "./native-command.js";
import {
createMockCommandInteraction,
@@ -153,6 +154,7 @@ async function expectBoundStatusCommandDispatch(params: {
describe("Discord native plugin command dispatch", () => {
beforeEach(() => {
vi.restoreAllMocks();
clearPluginCommands();
persistentBindingMocks.resolveConfiguredAcpBindingRecord.mockReset();
persistentBindingMocks.resolveConfiguredAcpBindingRecord.mockReturnValue(null);
persistentBindingMocks.ensureConfiguredAcpBindingSession.mockReset();
@@ -162,6 +164,54 @@ describe("Discord native plugin command dispatch", () => {
});
});
it("executes plugin commands from the real registry through the native Discord command path", async () => {
const cfg = createConfig();
const commandSpec: NativeCommandSpec = {
name: "pair",
description: "Pair",
acceptsArgs: true,
};
const command = createDiscordNativeCommand({
command: commandSpec,
cfg,
discordConfig: cfg.channels?.discord ?? {},
accountId: "default",
sessionPrefix: "discord:slash",
ephemeralDefault: true,
threadBindings: createNoopThreadBindingManager("default"),
});
const interaction = createInteraction();
expect(
registerPluginCommand("demo-plugin", {
name: "pair",
description: "Pair device",
acceptsArgs: true,
requireAuth: false,
handler: async ({ args }) => ({ text: `paired:${args ?? ""}` }),
}),
).toEqual({ ok: true });
const dispatchSpy = vi
.spyOn(dispatcherModule, "dispatchReplyWithDispatcher")
.mockResolvedValue({} as never);
await (command as { run: (interaction: unknown) => Promise<void> }).run(
Object.assign(interaction, {
options: {
getString: () => "now",
getBoolean: () => null,
getFocused: () => "",
},
}) as unknown,
);
expect(dispatchSpy).not.toHaveBeenCalled();
expect(interaction.reply).toHaveBeenCalledWith(
expect.objectContaining({ content: "paired:now" }),
);
});
it("executes matched plugin commands directly without invoking the agent dispatcher", async () => {
const cfg = createConfig();
const commandSpec: NativeCommandSpec = {