Slack tests: align slash harness runtime mocks

This commit is contained in:
joshavant
2026-03-18 22:06:19 -05:00
parent 22dab3ad18
commit be0329eda2
3 changed files with 64 additions and 76 deletions

View File

@@ -1,23 +1,6 @@
import type { WebClient } from "@slack/web-api";
import { vi } from "vitest";
vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/config-runtime")>();
return {
...actual,
loadConfig: () => ({}),
};
});
vi.mock("./accounts.js", () => ({
resolveSlackAccount: () => ({
accountId: "default",
botToken: "xoxb-test",
botTokenSource: "config",
config: {},
}),
}));
export type SlackEditTestClient = WebClient & {
chat: {
update: ReturnType<typeof vi.fn>;
@@ -33,8 +16,35 @@ export type SlackSendTestClient = WebClient & {
};
};
const slackBlockTestState = vi.hoisted(() => ({
account: {
accountId: "default",
botToken: "xoxb-test",
botTokenSource: "config",
config: {},
},
config: {},
}));
vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/config-runtime")>();
return {
...actual,
loadConfig: () => slackBlockTestState.config,
};
});
vi.mock("./accounts.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./accounts.js")>();
return {
...actual,
resolveSlackAccount: () => slackBlockTestState.account,
};
});
// Kept for compatibility with existing tests; mocks install at module evaluation.
export function installSlackBlockTestMocks() {
// Backward compatible no-op. Mocks are hoisted at module scope.
return;
}
export function createSlackEditTestClient(): SlackEditTestClient {

View File

@@ -202,37 +202,30 @@ vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => {
vi.mock("openclaw/plugin-sdk/reply-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/reply-runtime")>();
const replyResolver: typeof actual.getReplyFromConfig = (...args) =>
slackTestState.replyMock(...args) as ReturnType<typeof actual.getReplyFromConfig>;
return {
...actual,
dispatchInboundMessage: async (params: {
ctx: unknown;
replyOptions?: {
onReplyStart?: () => Promise<void> | void;
onAssistantMessageStart?: () => Promise<void> | void;
};
dispatcher: {
sendFinalReply: (payload: unknown) => boolean;
waitForIdle: () => Promise<void>;
markComplete: () => void;
};
}) => {
const reply = await slackTestState.replyMock(params.ctx, {
...params.replyOptions,
onReplyStart:
params.replyOptions?.onReplyStart ?? params.replyOptions?.onAssistantMessageStart,
});
const queuedFinal = reply ? params.dispatcher.sendFinalReply(reply) : false;
params.dispatcher.markComplete();
await params.dispatcher.waitForIdle();
return {
queuedFinal,
counts: {
tool: 0,
block: 0,
final: queuedFinal ? 1 : 0,
},
};
},
getReplyFromConfig: replyResolver,
dispatchInboundMessage: (params: Parameters<typeof actual.dispatchInboundMessage>[0]) =>
actual.dispatchInboundMessage({
...params,
replyResolver,
}),
dispatchInboundMessageWithBufferedDispatcher: (
params: Parameters<typeof actual.dispatchInboundMessageWithBufferedDispatcher>[0],
) =>
actual.dispatchInboundMessageWithBufferedDispatcher({
...params,
replyResolver,
}),
dispatchInboundMessageWithDispatcher: (
params: Parameters<typeof actual.dispatchInboundMessageWithDispatcher>[0],
) =>
actual.dispatchInboundMessageWithDispatcher({
...params,
replyResolver,
}),
};
});
@@ -246,9 +239,13 @@ vi.mock("./resolve-users.js", () => ({
entries.map((input) => ({ input, resolved: false })),
}));
vi.mock("./send.js", () => ({
sendMessageSlack: (...args: unknown[]) => slackTestState.sendMock(...args),
}));
vi.mock("./send.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./send.js")>();
return {
...actual,
sendMessageSlack: (...args: unknown[]) => slackTestState.sendMock(...args),
};
});
vi.mock("openclaw/plugin-sdk/conversation-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/conversation-runtime")>();
@@ -265,20 +262,12 @@ vi.mock("@slack/bolt", () => {
const { handlers, client: slackClient } = ensureSlackTestRuntime();
class App {
client = slackClient;
receiver = {
client: {
on: vi.fn(),
off: vi.fn(),
},
};
event(name: string, handler: SlackHandler) {
handlers.set(name, handler);
}
command = vi.fn();
action = vi.fn();
options = vi.fn();
view = vi.fn();
shortcut = vi.fn();
command() {
/* no-op */
}
start = vi.fn().mockResolvedValue(undefined);
stop = vi.fn().mockResolvedValue(undefined);
}

View File

@@ -7,7 +7,7 @@ const mocks = vi.hoisted(() => ({
resolveAgentRouteMock: vi.fn(),
finalizeInboundContextMock: vi.fn(),
resolveConversationLabelMock: vi.fn(),
createChannelReplyPipelineMock: vi.fn(),
createReplyPrefixOptionsMock: vi.fn(),
recordSessionMetaFromInboundMock: vi.fn(),
resolveStorePathMock: vi.fn(),
}));
@@ -43,27 +43,16 @@ vi.mock("openclaw/plugin-sdk/channel-runtime", async (importOriginal) => {
return {
...actual,
resolveConversationLabel: (...args: unknown[]) => mocks.resolveConversationLabelMock(...args),
createReplyPrefixOptions: (...args: unknown[]) => mocks.createReplyPrefixOptionsMock(...args),
recordInboundSessionMetaSafe: (...args: unknown[]) =>
mocks.recordSessionMetaFromInboundMock(...args),
};
});
vi.mock("openclaw/plugin-sdk/channel-reply-pipeline", async (importOriginal) => {
const actual =
await importOriginal<typeof import("openclaw/plugin-sdk/channel-reply-pipeline")>();
return {
...actual,
createChannelReplyPipeline: (...args: unknown[]) =>
mocks.createChannelReplyPipelineMock(...args),
};
});
vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/config-runtime")>();
return {
...actual,
recordSessionMetaFromInbound: (...args: unknown[]) =>
mocks.recordSessionMetaFromInboundMock(...args),
resolveStorePath: (...args: unknown[]) => mocks.resolveStorePathMock(...args),
};
});
@@ -75,7 +64,7 @@ type SlashHarnessMocks = {
resolveAgentRouteMock: ReturnType<typeof vi.fn>;
finalizeInboundContextMock: ReturnType<typeof vi.fn>;
resolveConversationLabelMock: ReturnType<typeof vi.fn>;
createChannelReplyPipelineMock: ReturnType<typeof vi.fn>;
createReplyPrefixOptionsMock: ReturnType<typeof vi.fn>;
recordSessionMetaFromInboundMock: ReturnType<typeof vi.fn>;
resolveStorePathMock: ReturnType<typeof vi.fn>;
};
@@ -95,7 +84,7 @@ export function resetSlackSlashMocks() {
});
mocks.finalizeInboundContextMock.mockReset().mockImplementation((ctx: unknown) => ctx);
mocks.resolveConversationLabelMock.mockReset().mockReturnValue(undefined);
mocks.createChannelReplyPipelineMock.mockReset().mockReturnValue({ onModelSelected: () => {} });
mocks.createReplyPrefixOptionsMock.mockReset().mockReturnValue({ onModelSelected: () => {} });
mocks.recordSessionMetaFromInboundMock.mockReset().mockResolvedValue(undefined);
mocks.resolveStorePathMock.mockReset().mockReturnValue("/tmp/openclaw-sessions.json");
}