test: trim extension test import churn

This commit is contained in:
Peter Steinberger 2026-04-03 04:37:34 +01:00
parent 2f013b68f8
commit 847faa3d04
No known key found for this signature in database
87 changed files with 293 additions and 286 deletions

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "./runtime-api.js";
const sendMessageBlueBubblesMock = vi.hoisted(() => vi.fn());
@ -17,11 +17,13 @@ vi.mock("../../../src/channels/plugins/bundled.js", () => ({
let bluebubblesPlugin: typeof import("./channel.js").bluebubblesPlugin;
describe("bluebubblesPlugin.pairing.notifyApproval", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ bluebubblesPlugin } = await import("./channel.js"));
});
beforeEach(() => {
sendMessageBlueBubblesMock.mockReset();
sendMessageBlueBubblesMock.mockResolvedValue({ messageId: "bb-pairing" });
({ bluebubblesPlugin } = await import("./channel.js"));
});
it("preserves accountId when sending pairing approvals", async () => {

View File

@ -86,7 +86,6 @@ async function expectThrownBrowserFetchError(
describe("fetchBrowserJson loopback auth", () => {
beforeAll(async () => {
vi.resetModules();
({ fetchBrowserJson } = await import("./client-fetch.js"));
});

View File

@ -10,7 +10,6 @@ let mod: typeof import("./pw-tools-core.js");
describe("pw-tools-core", () => {
beforeAll(async () => {
vi.resetModules();
mod = await import("./pw-tools-core.js");
});

View File

@ -35,7 +35,6 @@ let batchViaPlaywright: typeof import("./pw-tools-core.interactions.js").batchVi
describe("batchViaPlaywright", () => {
beforeAll(async () => {
vi.resetModules();
({ batchViaPlaywright } = await import("./pw-tools-core.interactions.js"));
});

View File

@ -13,7 +13,6 @@ let mod: typeof import("./pw-tools-core.js");
describe("pw-tools-core", () => {
beforeAll(async () => {
vi.resetModules();
mod = await import("./pw-tools-core.js");
});

View File

@ -27,7 +27,6 @@ function createFileChooserPageMocks() {
describe("pw-tools-core", () => {
beforeAll(async () => {
vi.resetModules();
mod = await import("./pw-tools-core.js");
});

View File

@ -57,7 +57,6 @@ let tmpDirModule: typeof import("../infra/tmp-openclaw-dir.js");
describe("pw-tools-core", () => {
beforeAll(async () => {
vi.resetModules();
vi.doMock("./pw-session.js", () => sessionMocks);
vi.doMock("./chrome.js", () => chromeMocks);
tmpDirModule = await import("../infra/tmp-openclaw-dir.js");

View File

@ -98,7 +98,6 @@ let registerBrowserAgentActRoutes: typeof import("./agent.act.js").registerBrows
let registerBrowserAgentSnapshotRoutes: typeof import("./agent.snapshot.js").registerBrowserAgentSnapshotRoutes;
beforeAll(async () => {
vi.resetModules();
({ registerBrowserAgentActRoutes } = await import("./agent.act.js"));
({ registerBrowserAgentSnapshotRoutes } = await import("./agent.snapshot.js"));
});

View File

@ -72,7 +72,6 @@ describe("browser control auth bootstrap failures", () => {
afterEach(async () => {
await stopBrowserControlServer();
vi.resetModules();
});
it("fails closed when auth bootstrap throws and no auth is configured", async () => {

View File

@ -70,7 +70,6 @@ let stopBrowserControlServer: typeof import("./server.js").stopBrowserControlSer
describe("browser control evaluate gating", () => {
beforeAll(async () => {
vi.resetModules();
({ startBrowserControlServerFromConfig, stopBrowserControlServer } =
await import("./server.js"));
});

View File

@ -28,7 +28,6 @@ describe("PlaywrightDiffScreenshotter", () => {
let cleanupRootDir: () => Promise<void>;
beforeAll(async () => {
vi.resetModules();
({ PlaywrightDiffScreenshotter, resetSharedBrowserStateForTests } =
await import("./browser.js"));
});

View File

@ -1,6 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createTestPluginApi } from "../../../test/helpers/plugins/plugin-api.js";
import type { OpenClawPluginApi } from "../api.js";
import type { DiffScreenshotter } from "./browser.js";
@ -16,11 +16,15 @@ vi.mock("./render.js", () => ({
}));
describe("diffs tool rendered output guards", () => {
let createDiffsTool: typeof import("./tool.js").createDiffsTool;
let cleanupRootDir: () => Promise<void>;
let store: Awaited<ReturnType<typeof createDiffStoreHarness>>["store"];
beforeAll(async () => {
({ createDiffsTool } = await import("./tool.js"));
});
beforeEach(async () => {
vi.resetModules();
renderDiffDocumentMock.mockReset();
({ store, cleanup: cleanupRootDir } = await createDiffStoreHarness(
"openclaw-diffs-tool-render-output-",
@ -39,7 +43,6 @@ describe("diffs tool rendered output guards", () => {
imageHtml: "",
});
const { createDiffsTool } = await import("./tool.js");
const screenshotter = createPngScreenshotter({
assertHtml: (html) => {
expect(html).toBe("");

View File

@ -296,7 +296,6 @@ beforeEach(() => {
});
beforeAll(async () => {
vi.resetModules();
({
buildExecApprovalCustomId,
extractDiscordChannelId,

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../runtime-api.js";
import { createFeishuCardInteractionEnvelope } from "./card-interaction.js";
import { looksLikeFeishuId, normalizeFeishuTarget, resolveReceiveIdType } from "./targets.js";
@ -101,12 +101,11 @@ async function expectLegacyFeishuCardPayloadRejected(cfg: OpenClawConfig, card:
expect(sendCardFeishuMock).not.toHaveBeenCalled();
}
describe("feishuPlugin.status.probeAccount", () => {
beforeEach(async () => {
vi.resetModules();
({ feishuPlugin } = await import("./channel.js"));
});
beforeAll(async () => {
({ feishuPlugin } = await import("./channel.js"));
});
describe("feishuPlugin.status.probeAccount", () => {
it("uses current account credentials for multi-account config", async () => {
const cfg = {
channels: {
@ -145,9 +144,7 @@ describe("feishuPlugin.status.probeAccount", () => {
});
describe("feishuPlugin.pairing.notifyApproval", () => {
beforeEach(async () => {
vi.resetModules();
({ feishuPlugin } = await import("./channel.js"));
beforeEach(() => {
sendMessageFeishuMock.mockReset();
sendMessageFeishuMock.mockResolvedValue({ messageId: "pairing-msg", chatId: "ou_user" });
});
@ -184,11 +181,6 @@ describe("feishuPlugin.pairing.notifyApproval", () => {
});
describe("feishuPlugin messaging", () => {
beforeEach(async () => {
vi.resetModules();
({ feishuPlugin } = await import("./channel.js"));
});
it("owns sender/topic session inheritance candidates", () => {
expect(
feishuPlugin.messaging?.resolveSessionConversation?.({

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createTestPluginApi } from "../../../test/helpers/plugins/plugin-api.js";
import { createPluginRuntimeMock } from "../../../test/helpers/plugins/plugin-runtime-mock.js";
import type { OpenClawPluginApi } from "../runtime-api.js";
@ -30,8 +30,11 @@ describe("registerFeishuChatTools", () => {
});
}
beforeAll(async () => {
({ registerFeishuChatTools } = await import("./chat.js"));
});
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
createFeishuClientMock.mockReturnValue({
im: {
@ -44,10 +47,6 @@ describe("registerFeishuChatTools", () => {
});
});
beforeEach(async () => {
({ registerFeishuChatTools } = await import("./chat.js"));
});
it("registers feishu_chat and handles info/members actions", async () => {
const registerTool = vi.fn();
registerFeishuChatTools(

View File

@ -133,7 +133,6 @@ function firstWsClientOptions(): { agent?: unknown } {
}
beforeAll(async () => {
vi.resetModules();
vi.doMock("@larksuiteoapi/node-sdk", () => ({
AppType: { SelfBuild: "self" },
Domain: { Feishu: "https://open.feishu.cn", Lark: "https://open.larksuite.com" },

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, test, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { createToolFactoryHarness } from "./tool-factory-test-harness.js";
@ -22,9 +22,11 @@ vi.mock("@larksuiteoapi/node-sdk", () => {
describe("feishu_doc account selection", () => {
let registerFeishuDocTools: typeof import("./docx.js").registerFeishuDocTools;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ registerFeishuDocTools } = await import("./docx.js"));
});
beforeEach(() => {
vi.clearAllMocks();
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createTestPluginApi } from "../../../test/helpers/plugins/plugin-api.js";
import { createPluginRuntimeMock } from "../../../test/helpers/plugins/plugin-runtime-mock.js";
import type { OpenClawPluginApi } from "../runtime-api.js";
@ -31,10 +31,12 @@ function createDriveToolApi(params: {
describe("registerFeishuDriveTools", () => {
const requestMock = vi.fn();
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
beforeAll(async () => {
({ registerFeishuDriveTools } = await import("./drive.js"));
});
beforeEach(() => {
vi.clearAllMocks();
resolveAnyEnabledFeishuToolsConfigMock.mockReturnValue({
doc: false,
chat: false,

View File

@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig } from "../runtime-api.js";
const createFeishuClientMock = vi.hoisted(() => vi.fn());
@ -82,14 +82,16 @@ function mockResolvedFeishuAccount() {
}
describe("sendMediaFeishu msg_type routing", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({
downloadImageFeishu,
downloadMessageResourceFeishu,
sanitizeFileNameForUpload,
sendMediaFeishu,
} = await import("./media.js"));
});
beforeEach(() => {
vi.clearAllMocks();
mockResolvedFeishuAccount();

View File

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const createFeishuClientMock = vi.hoisted(() => vi.fn());
@ -6,12 +6,6 @@ vi.mock("./client.js", () => ({
createFeishuClient: createFeishuClientMock,
}));
async function importProbeModule(scope: string) {
void scope;
vi.resetModules();
return await import("./probe.js");
}
let FEISHU_PROBE_REQUEST_TIMEOUT_MS: typeof import("./probe.js").FEISHU_PROBE_REQUEST_TIMEOUT_MS;
let probeFeishu: typeof import("./probe.js").probeFeishu;
let clearProbeCache: typeof import("./probe.js").clearProbeCache;
@ -106,10 +100,12 @@ async function readSequentialDefaultProbePair() {
}
describe("probeFeishu", () => {
beforeEach(async () => {
({ FEISHU_PROBE_REQUEST_TIMEOUT_MS, probeFeishu, clearProbeCache } = await importProbeModule(
`probe-${Date.now()}-${Math.random()}`,
));
beforeAll(async () => {
({ FEISHU_PROBE_REQUEST_TIMEOUT_MS, probeFeishu, clearProbeCache } =
await import("./probe.js"));
});
beforeEach(() => {
clearProbeCache();
vi.restoreAllMocks();
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig } from "../runtime-api.js";
const resolveFeishuAccountMock = vi.hoisted(() => vi.fn());
@ -19,9 +19,11 @@ describe("resolveFeishuSendTarget", () => {
const cfg = {} as ClawdbotConfig;
const client = { id: "client" };
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ resolveFeishuSendTarget } = await import("./send-target.js"));
});
beforeEach(() => {
resolveFeishuAccountMock.mockReset().mockReturnValue({
accountId: "default",
enabled: true,

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const resolveFeishuSendTargetMock = vi.hoisted(() => vi.fn());
const resolveMarkdownTableModeMock = vi.hoisted(() => vi.fn(() => "preserve"));
@ -42,9 +42,11 @@ describe("Feishu reply fallback for withdrawn/deleted targets", () => {
expect(result.messageId).toBe(expectedMessageId);
}
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ sendCardFeishu, sendMessageFeishu } = await import("./send.js"));
});
beforeEach(() => {
vi.clearAllMocks();
resolveFeishuSendTargetMock.mockReturnValue({
client: {

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig } from "../runtime-api.js";
const {
@ -59,8 +59,7 @@ let resolveFeishuCardTemplate: typeof import("./send.js").resolveFeishuCardTempl
let sendMessageFeishu: typeof import("./send.js").sendMessageFeishu;
describe("getMessageFeishu", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({
buildStructuredCard,
editMessageFeishu,
@ -69,6 +68,9 @@ describe("getMessageFeishu", () => {
resolveFeishuCardTemplate,
sendMessageFeishu,
} = await import("./send.js"));
});
beforeEach(() => {
vi.clearAllMocks();
mockResolveMarkdownTableMode.mockReturnValue("preserve");
mockConvertMarkdownTables.mockImplementation((text: string) => text);

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, test, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { createToolFactoryHarness } from "./tool-factory-test-harness.js";
@ -51,8 +51,7 @@ function createConfig(params: {
}
describe("feishu tool account routing", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ registerFeishuBitableTools, registerFeishuDriveTools, registerFeishuPermTools } =
await import("./bitable.js").then(async ({ registerFeishuBitableTools }) => ({
registerFeishuBitableTools,
@ -61,6 +60,9 @@ describe("feishu tool account routing", () => {
...(await import("./wiki.js")),
})));
({ registerFeishuWikiTools } = await import("./wiki.js"));
});
beforeEach(() => {
vi.clearAllMocks();
});

View File

@ -37,7 +37,6 @@ describe("firecrawl tools", () => {
let firecrawlClientTesting: typeof import("./firecrawl-client.js").__testing;
beforeAll(async () => {
vi.resetModules();
({ fetchFirecrawlContent } = await import("../api.js"));
({ createFirecrawlWebFetchProvider } = await import("./firecrawl-fetch-provider.js"));
({ createFirecrawlWebSearchProvider } = await import("./firecrawl-search-provider.js"));
@ -260,7 +259,6 @@ describe("firecrawl tools", () => {
});
it("passes proxy and storeInCache through the fetch provider tool", async () => {
const { createFirecrawlWebFetchProvider } = await import("./firecrawl-fetch-provider.js");
const provider = createFirecrawlWebFetchProvider();
const tool = provider.createTool({
config: { test: true },

View File

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const resolveIrcAccountMock = vi.hoisted(() => vi.fn());
const buildIrcConnectOptionsMock = vi.hoisted(() => vi.fn());
@ -19,12 +19,14 @@ vi.mock("./client.js", () => ({
let probeIrc: typeof import("./probe.js").probeIrc;
describe("probeIrc", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ probeIrc } = await import("./probe.js"));
});
beforeEach(() => {
resolveIrcAccountMock.mockReset();
buildIrcConnectOptionsMock.mockReset();
connectIrcClientMock.mockReset();
({ probeIrc } = await import("./probe.js"));
});
afterEach(() => {

View File

@ -214,7 +214,6 @@ async function startInflightReplayDuplicate(params: {
describe("handleLineWebhookEvents", () => {
beforeAll(async () => {
vi.resetModules();
({ handleLineWebhookEvents, createLineWebhookReplayCache } = await import("./bot-handlers.js"));
});

View File

@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const getMessageContentMock = vi.hoisted(() => vi.fn());
@ -38,13 +38,15 @@ async function* chunks(parts: Buffer[]): AsyncGenerator<Buffer> {
}
describe("downloadLineMedia", () => {
beforeEach(async () => {
vi.restoreAllMocks();
vi.resetModules();
getMessageContentMock.mockReset();
beforeAll(async () => {
({ downloadLineMedia } = await import("./download.js"));
});
beforeEach(() => {
vi.restoreAllMocks();
getMessageContentMock.mockReset();
});
it("does not derive temp file path from external messageId", async () => {
const messageId = "a/../../../../etc/passwd";
const jpeg = Buffer.from([0xff, 0xd8, 0xff, 0x00]);

View File

@ -46,7 +46,6 @@ function createMockClient() {
}
beforeAll(async () => {
vi.resetModules();
const runtimeModule = await import("../runtime.js");
runtimeModule.setMatrixRuntime(runtimeStub);
({ createMatrixDraftStream } = await import("./draft-stream.js"));

View File

@ -1,5 +1,5 @@
import { Type } from "@sinclair/typebox";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../runtime-api.js";
import { createChannelReplyPipeline } from "../runtime-api.js";
@ -108,10 +108,12 @@ function createMattermostActionContext(
}
describe("mattermostPlugin", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ mattermostPlugin } = await import("./channel.js"));
({ resetMattermostReactionBotUserCacheForTests } = await import("./mattermost/reactions.js"));
});
beforeEach(() => {
sendMessageMattermostMock.mockReset();
sendMessageMattermostMock.mockResolvedValue({
messageId: "post-1",

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const {
listMattermostAccountIdsMock,
@ -32,13 +32,15 @@ let listMattermostDirectoryGroups: typeof import("./directory.js").listMattermos
let listMattermostDirectoryPeers: typeof import("./directory.js").listMattermostDirectoryPeers;
describe("mattermost directory", () => {
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
beforeAll(async () => {
({ listMattermostDirectoryGroups, listMattermostDirectoryPeers } =
await import("./directory.js"));
});
beforeEach(() => {
vi.clearAllMocks();
});
it("deduplicates channels across enabled accounts and skips failing accounts", async () => {
const clientA = {
token: "token-a",

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const evaluateSenderGroupAccessForPolicy = vi.hoisted(() => vi.fn());
const isDangerousNameMatchingEnabled = vi.hoisted(() => vi.fn());
@ -15,8 +15,23 @@ vi.mock("./runtime-api.js", () => ({
}));
describe("mattermost monitor auth", () => {
let authorizeMattermostCommandInvocation: typeof import("./monitor-auth.js").authorizeMattermostCommandInvocation;
let isMattermostSenderAllowed: typeof import("./monitor-auth.js").isMattermostSenderAllowed;
let normalizeMattermostAllowEntry: typeof import("./monitor-auth.js").normalizeMattermostAllowEntry;
let normalizeMattermostAllowList: typeof import("./monitor-auth.js").normalizeMattermostAllowList;
let resolveMattermostEffectiveAllowFromLists: typeof import("./monitor-auth.js").resolveMattermostEffectiveAllowFromLists;
beforeAll(async () => {
({
authorizeMattermostCommandInvocation,
isMattermostSenderAllowed,
normalizeMattermostAllowEntry,
normalizeMattermostAllowList,
resolveMattermostEffectiveAllowFromLists,
} = await import("./monitor-auth.js"));
});
beforeEach(() => {
vi.resetModules();
evaluateSenderGroupAccessForPolicy.mockReset();
isDangerousNameMatchingEnabled.mockReset();
resolveAllowlistMatchSimple.mockReset();
@ -24,18 +39,12 @@ describe("mattermost monitor auth", () => {
resolveEffectiveAllowFromLists.mockReset();
});
it("normalizes allowlist entries and resolves effective lists", async () => {
it("normalizes allowlist entries and resolves effective lists", () => {
resolveEffectiveAllowFromLists.mockReturnValue({
effectiveAllowFrom: ["alice"],
effectiveGroupAllowFrom: ["team"],
});
const {
normalizeMattermostAllowEntry,
normalizeMattermostAllowList,
resolveMattermostEffectiveAllowFromLists,
} = await import("./monitor-auth.js");
expect(normalizeMattermostAllowEntry(" @Alice ")).toBe("alice");
expect(normalizeMattermostAllowEntry("mattermost:Bob")).toBe("bob");
expect(normalizeMattermostAllowEntry("*")).toBe("*");
@ -62,10 +71,8 @@ describe("mattermost monitor auth", () => {
});
});
it("checks sender allowlists against normalized ids and names", async () => {
it("checks sender allowlists against normalized ids and names", () => {
resolveAllowlistMatchSimple.mockReturnValue({ allowed: true });
const { isMattermostSenderAllowed } = await import("./monitor-auth.js");
expect(
isMattermostSenderAllowed({
senderId: "@Alice",
@ -98,8 +105,6 @@ describe("mattermost monitor auth", () => {
});
resolveAllowlistMatchSimple.mockReturnValue({ allowed: false });
const { authorizeMattermostCommandInvocation } = await import("./monitor-auth.js");
expect(
authorizeMattermostCommandInvocation({
account: {

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const fetchMattermostChannel = vi.hoisted(() => vi.fn());
const fetchMattermostUser = vi.hoisted(() => vi.fn());
@ -18,8 +18,13 @@ vi.mock("./interactions.js", () => ({
}));
describe("mattermost monitor resources", () => {
let createMattermostMonitorResources: typeof import("./monitor-resources.js").createMattermostMonitorResources;
beforeAll(async () => {
({ createMattermostMonitorResources } = await import("./monitor-resources.js"));
});
beforeEach(() => {
vi.resetModules();
fetchMattermostChannel.mockReset();
fetchMattermostUser.mockReset();
sendMattermostTyping.mockReset();
@ -36,7 +41,6 @@ describe("mattermost monitor resources", () => {
path: "/tmp/file.png",
contentType: "image/png",
}));
const { createMattermostMonitorResources } = await import("./monitor-resources.js");
const resources = createMattermostMonitorResources({
accountId: "default",
@ -78,7 +82,6 @@ describe("mattermost monitor resources", () => {
fetchMattermostChannel.mockResolvedValue({ id: "chan-1", name: "town-square" });
fetchMattermostUser.mockResolvedValue({ id: "user-1", username: "alice" });
buildButtonProps.mockReturnValue(undefined);
const { createMattermostMonitorResources } = await import("./monitor-resources.js");
const resources = createMattermostMonitorResources({
accountId: "default",
@ -128,7 +131,6 @@ describe("mattermost monitor resources", () => {
});
it("proxies typing indicators to the mattermost client helper", async () => {
const { createMattermostMonitorResources } = await import("./monitor-resources.js");
const client = {} as never;
const resources = createMattermostMonitorResources({

View File

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const listSkillCommandsForAgents = vi.hoisted(() => vi.fn());
const parseStrictPositiveInteger = vi.hoisted(() => vi.fn());
@ -40,8 +40,13 @@ vi.mock("./slash-state.js", () => ({
}));
describe("mattermost monitor slash", () => {
let registerMattermostMonitorSlashCommands: typeof import("./monitor-slash.js").registerMattermostMonitorSlashCommands;
beforeAll(async () => {
({ registerMattermostMonitorSlashCommands } = await import("./monitor-slash.js"));
});
beforeEach(() => {
vi.resetModules();
listSkillCommandsForAgents.mockReset();
parseStrictPositiveInteger.mockReset();
fetchMattermostUserTeams.mockReset();
@ -60,7 +65,6 @@ describe("mattermost monitor slash", () => {
it("returns early when slash commands are disabled", async () => {
resolveSlashCommandConfig.mockReturnValue({ enabled: false });
isSlashCommandsEnabled.mockReturnValue(false);
const { registerMattermostMonitorSlashCommands } = await import("./monitor-slash.js");
await registerMattermostMonitorSlashCommands({
client: {} as never,
@ -95,8 +99,6 @@ describe("mattermost monitor slash", () => {
error: vi.fn(),
};
const { registerMattermostMonitorSlashCommands } = await import("./monitor-slash.js");
await registerMattermostMonitorSlashCommands({
client: {} as never,
cfg: { gateway: { port: 18789 } } as never,
@ -157,8 +159,6 @@ describe("mattermost monitor slash", () => {
error: vi.fn(),
};
const { registerMattermostMonitorSlashCommands } = await import("./monitor-slash.js");
await registerMattermostMonitorSlashCommands({
client: {} as never,
cfg: { gateway: { customBindHost: "loopback" } } as never,

View File

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const resolveMattermostAccount = vi.fn();
const createMattermostClient = vi.fn();
@ -16,23 +16,34 @@ vi.mock("./client.js", () => ({
}));
describe("mattermost target resolution", () => {
let isExplicitMattermostTarget: typeof import("./target-resolution.js").isExplicitMattermostTarget;
let isMattermostId: typeof import("./target-resolution.js").isMattermostId;
let parseMattermostApiStatus: typeof import("./target-resolution.js").parseMattermostApiStatus;
let resolveMattermostOpaqueTarget: typeof import("./target-resolution.js").resolveMattermostOpaqueTarget;
let resetMattermostOpaqueTargetCacheForTests: typeof import("./target-resolution.js").resetMattermostOpaqueTargetCacheForTests;
beforeAll(async () => {
({
isExplicitMattermostTarget,
isMattermostId,
parseMattermostApiStatus,
resolveMattermostOpaqueTarget,
resetMattermostOpaqueTargetCacheForTests,
} = await import("./target-resolution.js"));
});
beforeEach(() => {
vi.resetModules();
resolveMattermostAccount.mockReset();
createMattermostClient.mockReset();
fetchMattermostUser.mockReset();
normalizeMattermostBaseUrl.mockClear();
});
afterEach(async () => {
const { resetMattermostOpaqueTargetCacheForTests } = await import("./target-resolution.js");
afterEach(() => {
resetMattermostOpaqueTargetCacheForTests();
});
it("recognizes explicit targets and ID-shaped values", async () => {
const { isExplicitMattermostTarget, isMattermostId, parseMattermostApiStatus } =
await import("./target-resolution.js");
it("recognizes explicit targets and ID-shaped values", () => {
expect(isExplicitMattermostTarget("@alice")).toBe(true);
expect(isExplicitMattermostTarget("#town-square")).toBe(true);
expect(isExplicitMattermostTarget("mattermost:chan")).toBe(true);
@ -46,8 +57,6 @@ describe("mattermost target resolution", () => {
it("resolves opaque ids as users and caches the result", async () => {
createMattermostClient.mockReturnValue({ client: true });
fetchMattermostUser.mockResolvedValue({ id: "abcd1234abcd1234abcd1234ab" });
const { resolveMattermostOpaqueTarget } = await import("./target-resolution.js");
const input = "abcd1234abcd1234abcd1234ab";
await expect(
@ -81,8 +90,6 @@ describe("mattermost target resolution", () => {
it("falls back to channel targets on 404 lookups", async () => {
createMattermostClient.mockReturnValue({ client: true });
fetchMattermostUser.mockRejectedValue(new Error("Mattermost API 404 Not Found"));
const { resolveMattermostOpaqueTarget } = await import("./target-resolution.js");
const input = "bcde1234abcd1234abcd1234ab";
await expect(
@ -105,8 +112,6 @@ describe("mattermost target resolution", () => {
});
createMattermostClient.mockReturnValue({ client: true });
fetchMattermostUser.mockResolvedValue({ id: "cdef1234abcd1234abcd1234ab" });
const { resolveMattermostOpaqueTarget } = await import("./target-resolution.js");
const input = "cdef1234abcd1234abcd1234ab";
await resolveMattermostOpaqueTarget({

View File

@ -1,7 +1,7 @@
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
let edgeTTS: typeof import("./tts.js").edgeTTS;
@ -25,15 +25,7 @@ const baseEdgeConfig = {
describe("edgeTTS empty audio validation", () => {
let tempDir: string | undefined;
beforeEach(async () => {
vi.resetModules();
vi.doMock("node-edge-tts", () => ({
EdgeTTS: class {
ttsPromise(text: string, filePath: string) {
return mockTtsPromise(text, filePath);
}
},
}));
beforeAll(async () => {
({ edgeTTS } = await import("./tts.js"));
});

View File

@ -1,5 +1,5 @@
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { msteamsSetupAdapter } from "./setup-core.js";
const resolveMSTeamsUserAllowlist = vi.hoisted(() => vi.fn());
@ -31,6 +31,12 @@ vi.mock("../../../src/channels/plugins/bundled.js", () => ({
}));
describe("msteams setup surface", () => {
let msteamsSetupWizard: typeof import("./setup-surface.js").msteamsSetupWizard;
beforeAll(async () => {
({ msteamsSetupWizard } = await import("./setup-surface.js"));
});
beforeEach(() => {
resolveMSTeamsUserAllowlist.mockReset();
resolveMSTeamsChannelAllowlist.mockReset();
@ -41,7 +47,6 @@ describe("msteams setup surface", () => {
afterEach(() => {
vi.unstubAllEnvs();
vi.resetModules();
});
it("always resolves to the default account", () => {
@ -78,7 +83,6 @@ describe("msteams setup surface", () => {
appId: "app",
});
hasConfiguredMSTeamsCredentials.mockReturnValue(false);
const { msteamsSetupWizard } = await import("./setup-surface.js");
expect(
msteamsSetupWizard.status.resolveConfigured({
@ -90,7 +94,6 @@ describe("msteams setup surface", () => {
it("reports configured status from configured credentials and renders status lines", async () => {
resolveMSTeamsCredentials.mockReturnValue(null);
hasConfiguredMSTeamsCredentials.mockReturnValue(true);
const { msteamsSetupWizard } = await import("./setup-surface.js");
expect(
msteamsSetupWizard.status.resolveConfigured({
@ -114,7 +117,6 @@ describe("msteams setup surface", () => {
resolveMSTeamsCredentials.mockReturnValue(null);
hasConfiguredMSTeamsCredentials.mockReturnValue(false);
const { msteamsSetupWizard } = await import("./setup-surface.js");
const result = await msteamsSetupWizard.finalize?.({
cfg: { channels: { msteams: { existing: true } } },
prompter: {
@ -149,7 +151,6 @@ describe("msteams setup surface", () => {
throw new Error(`Unexpected prompt: ${message}`);
});
const { msteamsSetupWizard } = await import("./setup-surface.js");
const result = await msteamsSetupWizard.finalize?.({
cfg: { channels: { msteams: {} } },
prompter: {

View File

@ -1,7 +1,7 @@
import { mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import {
escapeNextcloudTalkMarkdown,
formatNextcloudTalkCodeBlock,
@ -67,8 +67,7 @@ const tempDirs: string[] = [];
let nextcloudTalkPlugin: typeof import("./channel.js").nextcloudTalkPlugin;
let NextcloudTalkConfigSchema: typeof import("./config-schema.js").NextcloudTalkConfigSchema;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ nextcloudTalkPlugin } = await import("./channel.js"));
({ NextcloudTalkConfigSchema } = await import("./config-schema.js"));
});

View File

@ -74,7 +74,6 @@ describe("openshell cli helpers", () => {
describe("openshell backend manager", () => {
beforeAll(async () => {
vi.resetModules();
vi.doMock("./cli.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./cli.js")>();
return {

View File

@ -18,7 +18,6 @@ describe("searxng web search provider", () => {
let plugin: typeof import("../index.js").default;
beforeAll(async () => {
vi.resetModules();
({ createSearxngWebSearchProvider } = await import("./searxng-search-provider.js"));
({ default: plugin } = await import("../index.js"));
});

View File

@ -69,7 +69,6 @@ function mockSuccessfulMediaDownload(client: ReturnType<typeof createClient>) {
describe("downloadSlackFile", () => {
beforeAll(async () => {
vi.resetModules();
({ downloadSlackFile } = await import("./actions.js"));
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@slack/web-api", () => {
const WebClient = vi.fn(function WebClientMock(
@ -20,8 +20,7 @@ let SLACK_DEFAULT_RETRY_OPTIONS: typeof import("./client.js").SLACK_DEFAULT_RETR
let SLACK_WRITE_RETRY_OPTIONS: typeof import("./client.js").SLACK_WRITE_RETRY_OPTIONS;
let WebClient: ReturnType<typeof vi.fn>;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
const slackWebApi = await import("@slack/web-api");
({
createSlackWebClient,
@ -34,6 +33,10 @@ beforeEach(async () => {
WebClient = slackWebApi.WebClient as unknown as ReturnType<typeof vi.fn>;
});
beforeEach(() => {
WebClient.mockClear();
});
describe("slack web client config", () => {
it("applies the default retry config when none is provided", () => {
const options = resolveSlackWebClientOptions();

View File

@ -1,5 +1,5 @@
import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import {
flush,
getSlackClient,
@ -71,9 +71,11 @@ beforeEach(() => {
resetInboundDedupe();
});
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ monitorSlackProvider } = await import("./monitor.js"));
});
beforeEach(() => {
resetInboundDedupe();
resetSlackTestState({
messages: { responsePrefix: "PFX" },

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { expectPairingReplyText } from "../../../test/helpers/pairing-reply.js";
import {
defaultSlackTestConfig,
@ -21,12 +21,14 @@ let monitorSlackProvider: typeof import("./monitor.js").monitorSlackProvider;
const slackTestState = getSlackTestState();
const { sendMock, replyMock, reactMock, upsertPairingRequestMock } = slackTestState;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ resetInboundDedupe } = await import("openclaw/plugin-sdk/reply-runtime"));
({ HISTORY_CONTEXT_MARKER } = await import("../../../src/auto-reply/reply/history.js"));
({ CURRENT_MESSAGE_MARKER } = await import("../../../src/auto-reply/reply/mentions.js"));
({ monitorSlackProvider } = await import("./monitor.js"));
});
beforeEach(() => {
resetInboundDedupe();
resetSlackTestState(defaultSlackTestConfig());
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { SlackMonitorContext } from "./context.js";
const readStoreAllowFromForDmPolicyMock = vi.hoisted(() => vi.fn());
@ -25,10 +25,12 @@ function makeSlackCtx(allowFrom: string[]): SlackMonitorContext {
describe("resolveSlackEffectiveAllowFrom", () => {
const prevTtl = process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ clearSlackAllowFromCacheForTest, resolveSlackEffectiveAllowFrom } =
await import("./auth.js"));
});
beforeEach(() => {
readStoreAllowFromForDmPolicyMock.mockReset();
clearSlackAllowFromCacheForTest();
if (prevTtl === undefined) {

View File

@ -38,7 +38,6 @@ function createChannelContext(params?: {
describe("registerSlackChannelEvents", () => {
beforeAll(async () => {
vi.resetModules();
({ registerSlackChannelEvents } = await import("./channels.js"));
({ createSlackSystemEventTestHarness } = await import("./system-event-test-harness.js"));
});

View File

@ -71,7 +71,6 @@ async function runMemberCase(args: MemberCaseArgs = {}): Promise<void> {
describe("registerSlackMemberEvents", () => {
beforeAll(async () => {
vi.resetModules();
({ registerSlackMemberEvents } = await import("./members.js"));
({ createSlackSystemEventTestHarness: initSlackHarness } =
await import("./system-event-test-harness.js"));

View File

@ -58,7 +58,6 @@ function resetMessageMocks(): void {
}
beforeAll(async () => {
vi.resetModules();
({ registerSlackMessageEvents } = await import("./messages.js"));
});

View File

@ -75,7 +75,6 @@ async function runPinCase(input: PinCase = {}): Promise<void> {
describe("registerSlackPinEvents", () => {
beforeAll(async () => {
vi.resetModules();
({ registerSlackPinEvents } = await import("./pins.js"));
({ createSlackSystemEventTestHarness: buildPinHarness } =
await import("./system-event-test-harness.js"));

View File

@ -77,7 +77,6 @@ async function executeReactionCase(input: ReactionRunInput = {}) {
describe("registerSlackReactionEvents", () => {
beforeAll(async () => {
vi.resetModules();
({ registerSlackReactionEvents } = await import("./reactions.js"));
({ createSlackSystemEventTestHarness } = await import("./system-event-test-harness.js"));
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const prepareSlackMessageMock =
vi.fn<
@ -117,9 +117,11 @@ async function createInFlightMessageScenario(ts: string) {
}
describe("createSlackMessageHandler app_mention race handling", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ createSlackMessageHandler } = await import("./message-handler.js"));
});
beforeEach(() => {
prepareSlackMessageMock.mockReset();
dispatchPreparedSlackMessageMock.mockReset();
});

View File

@ -71,7 +71,6 @@ async function handleDirectMessage(
describe("createSlackMessageHandler", () => {
beforeAll(async () => {
vi.resetModules();
({ createSlackMessageHandler } = await import("./message-handler.js"));
});

View File

@ -1,5 +1,5 @@
import type { WebClient } from "@slack/web-api";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const editSlackMessageMock = vi.fn();
@ -24,12 +24,14 @@ function createClient(overrides?: {
}
describe("finalizeSlackPreviewEdit", () => {
beforeEach(async () => {
vi.resetModules();
editSlackMessageMock.mockReset();
beforeAll(async () => {
({ finalizeSlackPreviewEdit, __testing } = await import("./preview-finalize.js"));
});
beforeEach(() => {
editSlackMessageMock.mockReset();
});
it("treats a thrown edit as success when history readback already matches", async () => {
editSlackMessageMock.mockRejectedValueOnce(new Error("socket closed"));
const client = createClient({

View File

@ -22,7 +22,6 @@ function baseParams(overrides?: Record<string, unknown>) {
describe("deliverReplies identity passthrough", () => {
beforeAll(async () => {
vi.resetModules();
({ deliverReplies } = await import("./replies.js"));
});

View File

@ -1,5 +1,5 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const sendMessageSlackMock = vi.hoisted(() => vi.fn());
const getGlobalHookRunnerMock = vi.hoisted(() => vi.fn());
@ -73,11 +73,13 @@ const expectSlackSendCalledWith = (
};
describe("slack outbound hook wiring", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ slackOutbound } = await import("./outbound-adapter.js"));
});
beforeEach(() => {
vi.clearAllMocks();
sendMessageSlackMock.mockResolvedValue({ messageId: "1234.5678", channelId: "C123" });
({ slackOutbound } = await import("./outbound-adapter.js"));
});
afterEach(() => {

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const authTestMock = vi.hoisted(() => vi.fn());
const createSlackWebClientMock = vi.hoisted(() => vi.fn());
@ -15,8 +15,11 @@ vi.mock("openclaw/plugin-sdk/text-runtime", () => ({
let probeSlack: typeof import("./probe.js").probeSlack;
describe("probeSlack", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ probeSlack } = await import("./probe.js"));
});
beforeEach(() => {
authTestMock.mockReset();
createSlackWebClientMock.mockReset();
withTimeoutMock.mockReset();
@ -27,7 +30,6 @@ describe("probeSlack", () => {
},
});
withTimeoutMock.mockImplementation(async (promise: Promise<unknown>) => await promise);
({ probeSlack } = await import("./probe.js"));
});
it("maps Slack auth metadata on success", async () => {

View File

@ -1,5 +1,5 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import {
dispatchReplyWithBufferedBlockDispatcher,
finalizeInboundContextMock,
@ -15,11 +15,12 @@ type RegisteredRoute = {
};
let createSynologyChatPlugin: typeof import("./channel.js").createSynologyChatPlugin;
const freshChannelModulePath: string = "./channel.js?channel-integration-test";
describe("Synology channel wiring integration", () => {
beforeEach(async () => {
vi.resetModules();
({ createSynologyChatPlugin } = await import(freshChannelModulePath));
beforeAll(async () => {
({ createSynologyChatPlugin } = await import("./channel.js"));
});
beforeEach(() => {
registerPluginHttpRouteMock.mockClear();
dispatchReplyWithBufferedBlockDispatcher.mockClear();
finalizeInboundContextMock.mockClear();

View File

@ -1,5 +1,5 @@
import { EventEmitter } from "node:events";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { describe, it, expect, vi, beforeAll, beforeEach, afterEach } from "vitest";
// Mock http and https modules before importing the client
vi.mock("node:https", () => {
@ -54,9 +54,13 @@ function mockFailureResponse(statusCode = 500) {
}
function installFakeTimerHarness() {
beforeAll(async () => {
({ sendMessage, sendFileUrl, fetchChatUsers, resolveLegacyWebhookNameToChatUserId } =
await import("./client.js"));
});
beforeEach(() => {
vi.clearAllMocks();
vi.resetModules();
vi.useFakeTimers();
fakeNowMs += 10_000;
vi.setSystemTime(fakeNowMs);
@ -65,11 +69,6 @@ function installFakeTimerHarness() {
afterEach(() => {
vi.useRealTimers();
});
beforeEach(async () => {
({ sendMessage, sendFileUrl, fetchChatUsers, resolveLegacyWebhookNameToChatUserId } =
await import("./client.js"));
});
}
describe("sendMessage", () => {

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
// Capture every call to postTrustedWebToolsJson so we can assert on extraHeaders.
const postTrustedWebToolsJson = vi.fn();
@ -29,15 +29,16 @@ describe("tavily client X-Client-Source header", () => {
let runTavilySearch: typeof import("./tavily-client.js").runTavilySearch;
let runTavilyExtract: typeof import("./tavily-client.js").runTavilyExtract;
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ runTavilySearch, runTavilyExtract } = await import("./tavily-client.js"));
});
beforeEach(() => {
postTrustedWebToolsJson.mockReset();
postTrustedWebToolsJson.mockImplementation(
async (_params: unknown, parse: (r: Response) => Promise<unknown>) =>
parse(Response.json({ results: [] })),
);
({ runTavilySearch, runTavilyExtract } = await import("./tavily-client.js"));
});
it("runTavilySearch sends X-Client-Source: openclaw", async () => {

View File

@ -36,7 +36,6 @@ describe("tavily tools", () => {
let tavilyClientTesting: typeof import("./tavily-client.js").__testing;
beforeAll(async () => {
vi.resetModules();
({ createTavilyWebSearchProvider } = await import("./tavily-search-provider.js"));
({ createTavilySearchTool } = await import("./tavily-search-tool.js"));
({ createTavilyExtractTool } = await import("./tavily-extract-tool.js"));

View File

@ -1,5 +1,5 @@
import { createRequire } from "node:module";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { fetchTelegramChatId } from "./api-fetch.js";
const require = createRequire(import.meta.url);
@ -51,6 +51,12 @@ afterEach(() => {
vi.unstubAllEnvs();
});
vi.mock("undici", () => ({
ProxyAgent: proxyMocks.ProxyAgent,
fetch: proxyMocks.undiciFetch,
setGlobalDispatcher: proxyMocks.setGlobalDispatcher,
}));
describe("fetchTelegramChatId", () => {
const cases = [
{
@ -163,17 +169,14 @@ describe("undici env proxy semantics", () => {
});
describe("makeProxyFetch", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ getProxyUrlFromFetch, makeProxyFetch } = await import("./proxy.js"));
});
beforeEach(() => {
proxyMocks.undiciFetch.mockReset();
proxyMocks.proxyAgentSpy.mockClear();
proxyMocks.setGlobalDispatcher.mockClear();
vi.doMock("undici", () => ({
ProxyAgent: proxyMocks.ProxyAgent,
fetch: proxyMocks.undiciFetch,
setGlobalDispatcher: proxyMocks.setGlobalDispatcher,
}));
({ getProxyUrlFromFetch, makeProxyFetch } = await import("./proxy.js"));
});
it("attaches proxy metadata for resolver transport handling", () => {

View File

@ -136,7 +136,6 @@ function createConfiguredTelegramRoute() {
describe("buildTelegramMessageContext ACP configured bindings", () => {
beforeAll(async () => {
vi.resetModules();
({ buildTelegramMessageContextForTest } =
await import("./bot-message-context.test-harness.js"));
});

View File

@ -19,7 +19,6 @@ let createTelegramMessageProcessor: typeof import("./bot-message.js").createTele
describe("telegram bot message processor", () => {
beforeAll(async () => {
vi.resetModules();
({ createTelegramMessageProcessor } = await import("./bot-message.js"));
});

View File

@ -54,7 +54,6 @@ async function registerPairMenu(params: {
describe("registerTelegramNativeCommands real plugin registry", () => {
beforeAll(async () => {
vi.resetModules();
({ clearPluginCommands, registerPluginCommand } =
await import("../../../src/plugins/commands.js"));
({ registerTelegramNativeCommands } = await import("./bot-native-commands.js"));

View File

@ -387,7 +387,6 @@ function expectUnauthorizedNewCommandBlocked(sendMessage: ReturnType<typeof vi.f
describe("registerTelegramNativeCommands — session metadata", () => {
beforeAll(async () => {
vi.resetModules();
({ registerTelegramNativeCommands } = await import("./bot-native-commands.js"));
});

View File

@ -22,7 +22,6 @@ import {
describe("registerTelegramNativeCommands", () => {
beforeAll(async () => {
vi.resetModules();
({ registerTelegramNativeCommands, parseTelegramNativeCommandCallbackData } =
await import("./bot-native-commands.js"));
});

View File

@ -31,7 +31,6 @@ describe("fetchRemoteMedia telegram network policy", () => {
type LookupFn = NonNullable<Parameters<typeof fetchRemoteMedia>[0]["lookupFn"]>;
beforeAll(async () => {
vi.resetModules();
({ TEST_UNDICI_RUNTIME_DEPS_KEY } = await import("../../../src/infra/net/undici-runtime.js"));
({ fetchRemoteMedia } = await import("../../../src/media/fetch.js"));
({ resolveTelegramTransport, shouldRetryTelegramTransportFallback } =

View File

@ -80,7 +80,6 @@ let resolveTelegramFetch: typeof import("./fetch.js").resolveTelegramFetch;
let resolveTelegramTransport: typeof import("./fetch.js").resolveTelegramTransport;
beforeAll(async () => {
vi.resetModules();
({ resolveFetch } = await import("../../../src/infra/fetch.js"));
({ resolveTelegramFetch, resolveTelegramTransport } = await import("./fetch.js"));
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const runMock = vi.hoisted(() => vi.fn());
const createTelegramBotMock = vi.hoisted(() => vi.fn());
@ -135,14 +135,16 @@ function createPollingSessionWithTransportRestart(params: {
}
describe("TelegramPollingSession", () => {
beforeEach(async () => {
vi.resetModules();
beforeAll(async () => {
({ TelegramPollingSession } = await import("./polling-session.js"));
});
beforeEach(() => {
runMock.mockReset();
createTelegramBotMock.mockReset();
isRecoverableTelegramNetworkErrorMock.mockReset().mockReturnValue(true);
computeBackoffMock.mockReset().mockReturnValue(0);
sleepWithAbortMock.mockReset().mockResolvedValue(undefined);
({ TelegramPollingSession } = await import("./polling-session.js"));
});
it("uses backoff helpers for recoverable polling retries", async () => {

View File

@ -90,7 +90,6 @@ describe("telegram proxy client", () => {
};
beforeAll(async () => {
vi.resetModules();
({
deleteMessageTelegram,
reactMessageTelegram,

View File

@ -121,7 +121,6 @@ function resetTelegramWebhookMocks(): void {
}
beforeAll(async () => {
vi.resetModules();
({ startTelegramWebhook } = await import("./webhook.js"));
});

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const cryptoMocks = vi.hoisted(() => ({
randomBytes: vi.fn(),
@ -10,12 +10,14 @@ vi.mock("node:crypto", () => ({
let generateApprovalId: typeof import("./approval.js").generateApprovalId;
beforeEach(async () => {
vi.resetModules();
cryptoMocks.randomBytes.mockReset();
beforeAll(async () => {
({ generateApprovalId } = await import("./approval.js"));
});
beforeEach(() => {
cryptoMocks.randomBytes.mockReset();
});
describe("generateApprovalId", () => {
it("uses secure hex entropy while preserving the ID format", () => {
cryptoMocks.randomBytes.mockReturnValueOnce(Buffer.from("a1b2c3", "hex"));

View File

@ -86,7 +86,6 @@ async function expectReplySuppressed(replyResult: { text: string; isReasoning?:
describe("deliverWebReply", () => {
beforeAll(async () => {
vi.resetModules();
({ deliverWebReply } = await import("./deliver-reply.js"));
});

View File

@ -162,7 +162,6 @@ describe("runWebHeartbeatOnce", () => {
});
beforeAll(async () => {
vi.resetModules();
({ runWebHeartbeatOnce } = await import("./heartbeat-runner.js"));
});

View File

@ -11,7 +11,6 @@ setupAccessControlTestHarness();
let checkInboundAccessControl: typeof import("./access-control.js").checkInboundAccessControl;
beforeAll(async () => {
vi.resetModules();
({ checkInboundAccessControl } = await import("./access-control.js"));
});

View File

@ -2,7 +2,7 @@ import { EventEmitter } from "node:events";
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
import { resetLogger, setLoggerOverride } from "openclaw/plugin-sdk/runtime-env";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { renderQrPngBase64 } from "./qr-image.js";
vi.mock("./session.js", async () => {
@ -26,14 +26,16 @@ let loginWeb: typeof import("./login.js").loginWeb;
let createWaSocket: typeof import("./session.js").createWaSocket;
describe("web login", () => {
beforeEach(async () => {
vi.resetModules();
vi.useFakeTimers();
vi.clearAllMocks();
beforeAll(async () => {
({ loginWeb } = await import("./login.js"));
({ createWaSocket } = await import("./session.js"));
});
beforeEach(() => {
vi.useFakeTimers();
vi.clearAllMocks();
});
afterEach(() => {
vi.useRealTimers();
resetLogger();

View File

@ -77,7 +77,6 @@ let resolveTarget: NonNullable<
describe("whatsapp resolveTarget", () => {
beforeAll(async () => {
vi.resetModules();
const outbound = (await import("./channel.js")).whatsappPlugin.outbound;
if (!outbound?.resolveTarget) {
throw new Error("expected whatsapp outbound resolveTarget");

View File

@ -32,7 +32,6 @@ describe("web outbound", () => {
const sendReaction = vi.fn(async () => {});
beforeAll(async () => {
vi.resetModules();
({ sendMessageWhatsApp, sendPollWhatsApp, sendReactionWhatsApp } = await import("./send.js"));
({ setActiveWebListener } = await import("./active-listener.js"));
({ resetLogger, setLoggerOverride } = await import("openclaw/plugin-sdk/runtime-env"));

View File

@ -5,6 +5,7 @@ import "./zalo-js.test-mocks.js";
import type { ReplyPayload } from "../runtime-api.js";
import { zalouserPlugin } from "./channel.js";
import { setZalouserRuntime } from "./runtime.js";
import * as sendModule from "./send.js";
vi.mock("./send.js", () => ({
sendMessageZalouser: vi.fn().mockResolvedValue({ ok: true, messageId: "zlu-1" }),
@ -23,7 +24,7 @@ function baseCtx(payload: ReplyPayload) {
describe("zalouserPlugin outbound sendPayload", () => {
let mockedSend: ReturnType<typeof vi.mocked<(typeof import("./send.js"))["sendMessageZalouser"]>>;
beforeEach(async () => {
beforeEach(() => {
setZalouserRuntime({
channel: {
text: {
@ -32,8 +33,7 @@ describe("zalouserPlugin outbound sendPayload", () => {
},
},
} as never);
const mod = await import("./send.js");
mockedSend = vi.mocked(mod.sendMessageZalouser);
mockedSend = vi.mocked(sendModule.sendMessageZalouser);
primeChannelOutboundSendMock(mockedSend, { ok: true, messageId: "zlu-1" });
});

View File

@ -1,12 +1,8 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { describe, expect, it, vi } from "vitest";
describe("zca-client runtime loading", () => {
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
});
it("does not import zca-js until a session is created", async () => {
vi.clearAllMocks();
const runtimeFactory = vi.fn(() => ({
Zalo: class MockZalo {
constructor(public readonly options?: { logging?: boolean; selfListen?: boolean }) {}

View File

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { GeminiEmbeddingClient } from "./embeddings-gemini.js";
vi.mock("./remote-http.js", () => ({
@ -14,14 +14,16 @@ describe("runGeminiEmbeddingBatches", () => {
let withRemoteHttpResponse: typeof import("./remote-http.js").withRemoteHttpResponse;
let remoteHttpMock: ReturnType<typeof vi.mocked<typeof withRemoteHttpResponse>>;
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
beforeAll(async () => {
({ runGeminiEmbeddingBatches } = await import("./batch-gemini.js"));
({ withRemoteHttpResponse } = await import("./remote-http.js"));
remoteHttpMock = vi.mocked(withRemoteHttpResponse);
});
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("../../../../src/infra/retry.js", () => ({
retryAsync: vi.fn(async (run: () => Promise<unknown>) => await run()),
@ -15,10 +15,7 @@ describe("postJsonWithRetry", () => {
let postJsonMock: ReturnType<typeof vi.mocked<typeof import("./post-json.js").postJson>>;
let postJsonWithRetry: typeof import("./batch-http.js").postJsonWithRetry;
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
vi.resetModules();
beforeAll(async () => {
({ postJsonWithRetry } = await import("./batch-http.js"));
const retryModule = await import("../../../../src/infra/retry.js");
const postJsonModule = await import("./post-json.js");
@ -26,6 +23,10 @@ describe("postJsonWithRetry", () => {
postJsonMock = vi.mocked(postJsonModule.postJson);
});
beforeEach(() => {
vi.clearAllMocks();
});
it("posts JSON and returns parsed response payload", async () => {
postJsonMock.mockImplementationOnce(async (params) => {
return await params.parse({ ok: true, ids: [1, 2] });

View File

@ -71,7 +71,6 @@ let resolveGeminiOutputDimensionality: typeof import("./embeddings-gemini.js").r
beforeAll(async () => {
vi.doUnmock("undici");
vi.resetModules();
({
buildGeminiEmbeddingRequest,
buildGeminiTextEmbeddingRequest,

View File

@ -1,18 +1,21 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const postJsonMock = vi.hoisted(() => vi.fn());
vi.mock("./post-json.js", () => ({
postJson: postJsonMock,
}));
type EmbeddingsRemoteFetchModule = typeof import("./embeddings-remote-fetch.js");
let fetchRemoteEmbeddingVectors: EmbeddingsRemoteFetchModule["fetchRemoteEmbeddingVectors"];
describe("fetchRemoteEmbeddingVectors", () => {
beforeEach(async () => {
vi.resetModules();
vi.doMock("./post-json.js", () => ({
postJson: postJsonMock,
}));
beforeAll(async () => {
({ fetchRemoteEmbeddingVectors } = await import("./embeddings-remote-fetch.js"));
});
beforeEach(() => {
postJsonMock.mockReset();
});

View File

@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as authModule from "../../../../src/agents/model-auth.js";
import { type FetchMock, withFetchPreconnect } from "../../../../src/test-utils/fetch-mock.js";
import { mockPublicPinnedHostname } from "./test-helpers/ssrf.js";
@ -42,19 +43,19 @@ function installFetchMock(fetchMock: typeof globalThis.fetch) {
vi.stubGlobal("fetch", fetchMock);
}
let authModule: typeof import("../../../../src/agents/model-auth.js");
let createVoyageEmbeddingProvider: typeof import("./embeddings-voyage.js").createVoyageEmbeddingProvider;
let normalizeVoyageModel: typeof import("./embeddings-voyage.js").normalizeVoyageModel;
beforeEach(async () => {
vi.useRealTimers();
vi.doUnmock("undici");
vi.resetModules();
authModule = await import("../../../../src/agents/model-auth.js");
beforeAll(async () => {
({ createVoyageEmbeddingProvider, normalizeVoyageModel } =
await import("./embeddings-voyage.js"));
});
beforeEach(() => {
vi.useRealTimers();
vi.doUnmock("undici");
});
function mockVoyageApiKey() {
vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({
apiKey: "voyage-key-123",

View File

@ -1,5 +1,5 @@
import { setTimeout as sleep } from "node:timers/promises";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_GEMINI_EMBEDDING_MODEL } from "./embeddings-gemini.js";
import { mockPublicPinnedHostname } from "./test-helpers/ssrf.js";
@ -54,7 +54,7 @@ let nodeLlamaModule: typeof import("./node-llama.js");
let createEmbeddingProvider: EmbeddingsModule["createEmbeddingProvider"];
let DEFAULT_LOCAL_MODEL: EmbeddingsModule["DEFAULT_LOCAL_MODEL"];
beforeEach(async () => {
beforeAll(async () => {
vi.resetModules();
authModule = await import("../../../../src/agents/model-auth.js");
nodeLlamaModule = await import("./node-llama.js");
@ -63,6 +63,10 @@ beforeEach(async () => {
({ createEmbeddingProvider, DEFAULT_LOCAL_MODEL } = await import("./embeddings.js"));
});
beforeEach(() => {
vi.useRealTimers();
});
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
@ -575,11 +579,6 @@ describe("local embedding ensureContext concurrency", () => {
vi.doUnmock("./node-llama.js");
});
afterEach(() => {
vi.resetModules();
vi.doUnmock("./node-llama.js");
});
async function setupLocalProviderWithMockedInit(params?: {
initializationDelayMs?: number;
failFirstGetLlama?: boolean;
@ -708,6 +707,7 @@ describe("FTS-only fallback when no provider available", () => {
beforeEach(async () => {
authModule = await import("../../../../src/agents/model-auth.js");
({ createEmbeddingProvider, DEFAULT_LOCAL_MODEL } = await import("./embeddings.js"));
vi.spyOn(authModule, "resolveApiKeyForProvider");
});
it("returns null provider when all requested auth paths fail", async () => {

View File

@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("./remote-http.js", () => ({
withRemoteHttpResponse: vi.fn(),
@ -10,15 +10,16 @@ let withRemoteHttpResponse: typeof import("./remote-http.js").withRemoteHttpResp
describe("postJson", () => {
let remoteHttpMock: ReturnType<typeof vi.mocked<typeof withRemoteHttpResponse>>;
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
vi.resetModules();
beforeAll(async () => {
({ postJson } = await import("./post-json.js"));
({ withRemoteHttpResponse } = await import("./remote-http.js"));
remoteHttpMock = vi.mocked(withRemoteHttpResponse);
});
beforeEach(() => {
vi.clearAllMocks();
});
it("parses JSON payload on successful response", async () => {
remoteHttpMock.mockImplementationOnce(async (params) => {
return await params.onResponse(