test: route extension tests through sdk seams

This commit is contained in:
Peter Steinberger
2026-04-27 22:34:12 +01:00
parent 46ba8e7cce
commit a8c548f4f3
16 changed files with 60 additions and 87 deletions

View File

@@ -108,15 +108,6 @@ vi.mock("./browser/config.js", () => browserConfigMocks);
const nodesUtilsMocks = vi.hoisted(() => ({
listNodes: vi.fn(async (..._args: unknown[]): Promise<Array<Record<string, unknown>>> => []),
}));
vi.mock("../../../src/agents/tools/nodes-utils.js", async () => {
const actual = await vi.importActual<typeof import("../../../src/agents/tools/nodes-utils.js")>(
"../../../src/agents/tools/nodes-utils.js",
);
return {
...actual,
listNodes: nodesUtilsMocks.listNodes,
};
});
const gatewayMocks = vi.hoisted(() => ({
callGatewayTool: vi.fn(
@@ -126,7 +117,6 @@ const gatewayMocks = vi.hoisted(() => ({
}),
),
}));
vi.mock("../../../src/agents/tools/gateway.js", () => gatewayMocks);
const configMocks = vi.hoisted(() => ({
loadConfig: vi.fn<
@@ -156,13 +146,15 @@ vi.mock("./browser/session-tab-registry.js", () => sessionTabRegistryMocks);
const toolCommonMocks = vi.hoisted(() => ({
imageResultFromFile: vi.fn(),
}));
vi.mock("../../../src/agents/tools/common.js", async () => {
const actual = await vi.importActual<typeof import("../../../src/agents/tools/common.js")>(
"../../../src/agents/tools/common.js",
vi.mock("openclaw/plugin-sdk/browser-setup-tools", async () => {
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/browser-setup-tools")>(
"openclaw/plugin-sdk/browser-setup-tools",
);
return {
...actual,
callGatewayTool: gatewayMocks.callGatewayTool,
imageResultFromFile: toolCommonMocks.imageResultFromFile,
listNodes: nodesUtilsMocks.listNodes,
};
});

View File

@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
const ensureConfiguredBindingRouteReadyMock = vi.hoisted(() => vi.fn());
const resolveConfiguredBindingRouteMock = vi.hoisted(() => vi.fn());
vi.mock("../../../../src/channels/plugins/binding-routing.js", async () => {
vi.mock("openclaw/plugin-sdk/conversation-runtime", async () => {
const { createConfiguredBindingConversationRuntimeModuleMock } =
await import("../test-support/configured-binding-runtime.js");
return await createConfiguredBindingConversationRuntimeModuleMock(
@@ -13,8 +13,8 @@ vi.mock("../../../../src/channels/plugins/binding-routing.js", async () => {
resolveConfiguredBindingRouteMock,
},
() =>
vi.importActual<typeof import("../../../../src/channels/plugins/binding-routing.js")>(
"../../../../src/channels/plugins/binding-routing.js",
vi.importActual<typeof import("openclaw/plugin-sdk/conversation-runtime")>(
"openclaw/plugin-sdk/conversation-runtime",
),
);
});

View File

@@ -13,10 +13,10 @@ vi.mock("openclaw/plugin-sdk/plugin-config-runtime", async () => {
};
});
vi.mock("../../../src/infra/channel-activity.js", async () => {
const actual = await vi.importActual<typeof import("../../../src/infra/channel-activity.js")>(
"../../../src/infra/channel-activity.js",
);
vi.mock("openclaw/plugin-sdk/channel-activity-runtime", async () => {
const actual = await vi.importActual<
typeof import("openclaw/plugin-sdk/channel-activity-runtime")
>("openclaw/plugin-sdk/channel-activity-runtime");
return {
...actual,
recordChannelActivity: (...args: unknown[]) => recordChannelActivityMock(...args),

View File

@@ -34,15 +34,6 @@ const maybeCreateMatrixMigrationSnapshotMock = vi.hoisted(() =>
})),
);
vi.mock("../../../../../src/infra/backup-create.js", async () => {
const actual = await vi.importActual<typeof import("../../../../../src/infra/backup-create.js")>(
"../../../../../src/infra/backup-create.js",
);
return {
...actual,
createBackupArchive: (params: unknown) => createBackupArchiveMock(params),
};
});
vi.mock("./migration-snapshot.runtime.js", () => ({
maybeCreateMatrixMigrationSnapshot: (params: unknown) =>
maybeCreateMatrixMigrationSnapshotMock(params),

View File

@@ -2,6 +2,11 @@ import { mkdtempSync, writeFileSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import {
finalizeDebugProxyCapture,
getDebugProxyCaptureStore,
initializeDebugProxyCapture,
} from "openclaw/plugin-sdk/proxy-capture";
import { afterEach, describe, expect, it, vi } from "vitest";
import { installDebugProxyTestResetHooks } from "../test-support/debug-proxy-env-test-helpers.js";
@@ -81,7 +86,6 @@ describe("listMicrosoftVoices", () => {
new Response(JSON.stringify([{ ShortName: "en-US-AvaNeural" }]), { status: 200 }),
) as unknown as typeof globalThis.fetch;
const { getDebugProxyCaptureStore } = await import("../../src/proxy-capture/store.sqlite.js");
const store = getDebugProxyCaptureStore(
process.env.OPENCLAW_DEBUG_PROXY_DB_PATH,
process.env.OPENCLAW_DEBUG_PROXY_BLOB_DIR,
@@ -122,9 +126,6 @@ describe("listMicrosoftVoices", () => {
async () => new Response(JSON.stringify([{ ShortName: "en-US-AvaNeural" }]), { status: 200 }),
) as unknown as typeof globalThis.fetch;
const { getDebugProxyCaptureStore } = await import("../../src/proxy-capture/store.sqlite.js");
const { finalizeDebugProxyCapture, initializeDebugProxyCapture } =
await import("../../src/proxy-capture/runtime.js");
const store = getDebugProxyCaptureStore(
process.env.OPENCLAW_DEBUG_PROXY_DB_PATH,
process.env.OPENCLAW_DEBUG_PROXY_BLOB_DIR,

View File

@@ -1,7 +1,5 @@
import { describe, expect, it } from "vitest";
// Import the schema directly to avoid cross-extension import chains
const { MSTeamsConfigSchema } = await import("../../../src/config/zod-schema.providers-core.js");
import { MSTeamsConfigSchema } from "../config-api.js";
describe("MSTeamsConfigSchema blockStreaming", () => {
const baseConfig = {

View File

@@ -1,6 +1,11 @@
import { mkdtempSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import {
finalizeDebugProxyCapture,
getDebugProxyCaptureStore,
initializeDebugProxyCapture,
} from "openclaw/plugin-sdk/proxy-capture";
import { describe, expect, it, vi } from "vitest";
import { installDebugProxyTestResetHooks } from "../test-support/debug-proxy-env-test-helpers.js";
import { createStreamingErrorResponse } from "../test-support/streaming-error-response.js";
@@ -255,7 +260,6 @@ describe("openai tts", () => {
new Response(Buffer.from("audio-bytes"), { status: 200 }),
) as unknown as typeof globalThis.fetch;
const { getDebugProxyCaptureStore } = await import("../../src/proxy-capture/store.sqlite.js");
const store = getDebugProxyCaptureStore(
process.env.OPENCLAW_DEBUG_PROXY_DB_PATH,
process.env.OPENCLAW_DEBUG_PROXY_BLOB_DIR,
@@ -304,9 +308,7 @@ describe("openai tts", () => {
new Response(Buffer.from("audio-bytes"), { status: 200 }),
) as unknown as typeof globalThis.fetch;
const runtime = await import("../../src/proxy-capture/runtime.js");
const { getDebugProxyCaptureStore } = await import("../../src/proxy-capture/store.sqlite.js");
runtime.initializeDebugProxyCapture("test");
initializeDebugProxyCapture("test");
await openaiTTS({
text: "hello",
@@ -318,7 +320,7 @@ describe("openai tts", () => {
timeoutMs: 5_000,
});
await new Promise((resolve) => setTimeout(resolve, 0));
runtime.finalizeDebugProxyCapture();
finalizeDebugProxyCapture();
const store = getDebugProxyCaptureStore(
process.env.OPENCLAW_DEBUG_PROXY_DB_PATH,

View File

@@ -34,9 +34,9 @@ vi.mock("../send.js", () => ({
sendReadReceiptSignal: sendReadReceiptMock,
}));
vi.mock("../../../../src/auto-reply/dispatch.js", async () => {
const actual = await vi.importActual<typeof import("../../../../src/auto-reply/dispatch.js")>(
"../../../../src/auto-reply/dispatch.js",
vi.mock("openclaw/plugin-sdk/reply-runtime", async () => {
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/reply-runtime")>(
"openclaw/plugin-sdk/reply-runtime",
);
return {
...actual,

View File

@@ -1,3 +1,6 @@
import { CURRENT_MESSAGE_MARKER } from "openclaw/plugin-sdk/channel-mention-gating";
import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-dedupe";
import { HISTORY_CONTEXT_MARKER } from "openclaw/plugin-sdk/reply-history";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { expectPairingReplyText } from "../../../test/helpers/pairing-reply.js";
import {
@@ -13,17 +16,7 @@ import {
stopSlackMonitor,
} from "./monitor.test-helpers.js";
const [
{ resetInboundDedupe },
{ HISTORY_CONTEXT_MARKER },
{ CURRENT_MESSAGE_MARKER },
{ monitorSlackProvider },
] = await Promise.all([
import("../../../src/auto-reply/reply/inbound-dedupe.js"),
import("../../../src/auto-reply/reply/history.js"),
import("../../../src/auto-reply/reply/mentions.js"),
import("./monitor/provider.js"),
]);
const { monitorSlackProvider } = await import("./monitor/provider.js");
const slackTestState = getSlackTestState();
const { sendMock, replyMock, reactMock, upsertPairingRequestMock } = slackTestState;

View File

@@ -1,3 +1,7 @@
import {
clearRuntimeConfigSnapshot,
setRuntimeConfigSnapshot,
} from "openclaw/plugin-sdk/config-runtime";
import { vi, type Mock } from "vitest";
import { finalizeTelegramInboundContextForTest } from "./bot-message-context.session-runtime-test-support.js";
@@ -34,13 +38,8 @@ export const telegramRouteTestSessionRuntime = {
} satisfies TelegramTestSessionRuntime;
export async function loadTelegramMessageContextRouteHarness() {
const [
{ clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot },
{ buildTelegramMessageContextForTest },
] = await Promise.all([
import("../../../src/config/config.js"),
import("./bot-message-context.test-harness.js"),
]);
const { buildTelegramMessageContextForTest } =
await import("./bot-message-context.test-harness.js");
const buildTelegramMessageContextForRouteTest = (
params: BuildTelegramMessageContextForTestParams,
) =>

View File

@@ -1,9 +1,8 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import { clearPluginCommands, registerPluginCommand } from "openclaw/plugin-sdk/plugin-runtime";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
let registerTelegramNativeCommands: typeof import("./bot-native-commands.js").registerTelegramNativeCommands;
let clearPluginCommands: typeof import("../../../src/plugins/commands.js").clearPluginCommands;
let registerPluginCommand: typeof import("../../../src/plugins/commands.js").registerPluginCommand;
let setActivePluginRegistry: typeof import("openclaw/plugin-sdk/testing").setActivePluginRegistry;
let createCommandBot: typeof import("./bot-native-commands.menu-test-support.js").createCommandBot;
let createNativeCommandTestParams: typeof import("./bot-native-commands.menu-test-support.js").createNativeCommandTestParams;
@@ -113,8 +112,6 @@ async function registerPairMenu(params: {
describe("registerTelegramNativeCommands real plugin registry", () => {
beforeAll(async () => {
({ clearPluginCommands, registerPluginCommand } =
await import("../../../src/plugins/commands.js"));
({ setActivePluginRegistry } = await import("openclaw/plugin-sdk/testing"));
({ registerTelegramNativeCommands } = await import("./bot-native-commands.js"));
({

View File

@@ -18,7 +18,7 @@ type ResolveConfiguredBindingRouteFn =
type EnsureConfiguredBindingRouteReadyFn =
typeof import("openclaw/plugin-sdk/conversation-runtime").ensureConfiguredBindingRouteReady;
type DispatchReplyWithBufferedBlockDispatcherFn =
typeof import("../../../src/auto-reply/reply/provider-dispatcher.js").dispatchReplyWithBufferedBlockDispatcher;
typeof import("openclaw/plugin-sdk/reply-dispatch-runtime").dispatchReplyWithBufferedBlockDispatcher;
type DispatchReplyWithBufferedBlockDispatcherParams =
Parameters<DispatchReplyWithBufferedBlockDispatcherFn>[0];
type DispatchReplyWithBufferedBlockDispatcherResult = Awaited<
@@ -170,14 +170,17 @@ vi.mock("./bot-native-commands.runtime.js", async () => {
dispatchReplyWithBufferedBlockDispatcher: replyMocks.dispatchReplyWithBufferedBlockDispatcher,
};
});
vi.mock("../../../src/pairing/pairing-store.js", () => ({
readChannelAllowFromStore: vi.fn(async () => []),
}));
vi.mock("../../../src/plugins/commands.js", () => ({
getPluginCommandSpecs: vi.fn(() => []),
matchPluginCommand: vi.fn(() => null),
executePluginCommand: vi.fn(async () => ({ text: "ok" })),
}));
vi.mock("openclaw/plugin-sdk/plugin-runtime", async () => {
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/plugin-runtime")>(
"openclaw/plugin-sdk/plugin-runtime",
);
return {
...actual,
getPluginCommandSpecs: vi.fn(() => []),
matchPluginCommand: vi.fn(() => null),
executePluginCommand: vi.fn(async () => ({ text: "ok" })),
};
});
vi.mock("./bot/delivery.js", () => ({
deliverReplies: deliveryMocks.deliverReplies,
}));
@@ -237,8 +240,7 @@ function registerAndResolveCommandHandlerBase(params: {
const telegramDeps: TelegramNativeCommandDeps = {
getRuntimeConfig: vi.fn(() => cfg),
readChannelAllowFromStore: vi.fn(async () => []),
dispatchReplyWithBufferedBlockDispatcher:
replyMocks.dispatchReplyWithBufferedBlockDispatcher as TelegramNativeCommandDeps["dispatchReplyWithBufferedBlockDispatcher"],
dispatchReplyWithBufferedBlockDispatcher: replyMocks.dispatchReplyWithBufferedBlockDispatcher,
getPluginCommandSpecs: vi.fn(() => []),
listSkillCommandsForAgents: vi.fn(() => []),
syncTelegramMenuCommands: vi.fn(),

View File

@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import { listSkillCommandsForAgents as listActualSkillCommandsForAgents } from "openclaw/plugin-sdk/skill-commands-runtime";
import { afterEach, describe, expect, it, vi } from "vitest";
import { registerTelegramNativeCommands } from "./bot-native-commands.js";
import {
@@ -58,10 +59,9 @@ describe("registerTelegramNativeCommands skill allowlist integration", () => {
},
],
};
const actualSkillCommands = await import("../../../src/auto-reply/skill-commands.js");
listSkillCommandsForAgents.mockImplementation(
({ cfg, agentIds }: { cfg: OpenClawConfig; agentIds?: string[] }) =>
actualSkillCommands.listSkillCommandsForAgents({ cfg, agentIds }),
listActualSkillCommandsForAgents({ cfg, agentIds }),
);
registerTelegramNativeCommands({

View File

@@ -1,3 +1,7 @@
import {
listNativeCommandSpecs,
listNativeCommandSpecsForConfig,
} from "openclaw/plugin-sdk/native-command-registry";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../runtime-api.js";
@@ -9,8 +13,6 @@ const {
telegramBotRuntimeForTest,
} = await import("./bot.create-telegram-bot.test-harness.js");
let listNativeCommandSpecs: typeof import("../../../src/auto-reply/commands-registry.js").listNativeCommandSpecs;
let listNativeCommandSpecsForConfig: typeof import("../../../src/auto-reply/commands-registry.js").listNativeCommandSpecsForConfig;
let normalizeTelegramCommandName: typeof import("./command-config.js").normalizeTelegramCommandName;
let createTelegramBotBase: typeof import("./bot-core.js").createTelegramBotCore;
let setTelegramBotRuntimeForTest: typeof import("./bot-core.js").setTelegramBotRuntimeForTest;
@@ -46,8 +48,6 @@ function resolveSkillCommands(config: Parameters<typeof listNativeCommandSpecsFo
describe("createTelegramBot command menu", () => {
beforeAll(async () => {
({ listNativeCommandSpecs, listNativeCommandSpecsForConfig } =
await import("../../../src/auto-reply/commands-registry.js"));
({ normalizeTelegramCommandName } = await import("./command-config.js"));
({ createTelegramBotCore: createTelegramBotBase, setTelegramBotRuntimeForTest } =
await import("./bot-core.js"));

View File

@@ -4,6 +4,7 @@ import {
clearPluginInteractiveHandlers,
registerPluginInteractiveHandler,
} from "openclaw/plugin-sdk/plugin-runtime";
import { loadSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
import { mockPinnedHostnameResolution } from "openclaw/plugin-sdk/testing";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { TelegramInteractiveHandlerContext } from "./interactive-dispatch.js";
@@ -30,7 +31,6 @@ const {
wasSentByBot,
} = await import("./bot.create-telegram-bot.test-harness.js");
let loadSessionStore: typeof import("../../../src/config/sessions.js").loadSessionStore;
let createTelegramBotBase: typeof import("./bot-core.js").createTelegramBotCore;
let setTelegramBotRuntimeForTest: typeof import("./bot-core.js").setTelegramBotRuntimeForTest;
let createTelegramBot: (
@@ -82,7 +82,6 @@ async function loadInboundContextContract() {
const ORIGINAL_TZ = process.env.TZ;
describe("createTelegramBot", () => {
beforeAll(async () => {
({ loadSessionStore } = await import("../../../src/config/sessions.js"));
({ createTelegramBotCore: createTelegramBotBase, setTelegramBotRuntimeForTest } =
await import("./bot-core.js"));
});

View File

@@ -1,3 +1,4 @@
import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const setDefaultResultOrder = vi.hoisted(() => vi.fn());
@@ -96,7 +97,6 @@ vi.mock("openclaw/plugin-sdk/runtime-env", () => ({
isWSL2Sync: () => false,
}));
let resolveFetch: typeof import("../../../src/infra/fetch.js").resolveFetch;
let resolveTelegramFetch: typeof import("./fetch.js").resolveTelegramFetch;
let resolveTelegramTransport: typeof import("./fetch.js").resolveTelegramTransport;
@@ -105,7 +105,6 @@ type TelegramDispatcherPolicy = NonNullable<
>[number]["dispatcherPolicy"];
beforeAll(async () => {
({ resolveFetch } = await import("../../../src/infra/fetch.js"));
({ resolveTelegramFetch, resolveTelegramTransport } = await import("./fetch.js"));
});