From 2f13758f429728fd787a9e2e69801ab9196f4dd8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 27 Mar 2026 18:55:05 +0000 Subject: [PATCH] test: stabilize extension ci mocks --- .../src/mattermost/monitor-auth.test.ts | 11 ++++++++++- .../src/mattermost/monitor-resources.test.ts | 11 ++++++++++- .../src/mattermost/monitor-slash.test.ts | 15 ++++++++++++++- .../mattermost/src/mattermost/send.test.ts | 17 ++++++++++++----- .../mattermost/slash-http.send-config.test.ts | 6 ++++-- .../src/mattermost/target-resolution.test.ts | 1 + extensions/slack/src/channel.test.ts | 15 ++++++++------- 7 files changed, 59 insertions(+), 17 deletions(-) diff --git a/extensions/mattermost/src/mattermost/monitor-auth.test.ts b/extensions/mattermost/src/mattermost/monitor-auth.test.ts index 45f857e9021..cbc2ccd06ce 100644 --- a/extensions/mattermost/src/mattermost/monitor-auth.test.ts +++ b/extensions/mattermost/src/mattermost/monitor-auth.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; const evaluateSenderGroupAccessForPolicy = vi.hoisted(() => vi.fn()); const isDangerousNameMatchingEnabled = vi.hoisted(() => vi.fn()); @@ -15,6 +15,15 @@ vi.mock("../runtime-api.js", () => ({ })); describe("mattermost monitor auth", () => { + beforeEach(() => { + vi.resetModules(); + evaluateSenderGroupAccessForPolicy.mockReset(); + isDangerousNameMatchingEnabled.mockReset(); + resolveAllowlistMatchSimple.mockReset(); + resolveControlCommandGate.mockReset(); + resolveEffectiveAllowFromLists.mockReset(); + }); + it("normalizes allowlist entries and resolves effective lists", async () => { resolveEffectiveAllowFromLists.mockReturnValue({ effectiveAllowFrom: ["alice"], diff --git a/extensions/mattermost/src/mattermost/monitor-resources.test.ts b/extensions/mattermost/src/mattermost/monitor-resources.test.ts index 1438fa45bc6..26034cca516 100644 --- a/extensions/mattermost/src/mattermost/monitor-resources.test.ts +++ b/extensions/mattermost/src/mattermost/monitor-resources.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; const fetchMattermostChannel = vi.hoisted(() => vi.fn()); const fetchMattermostUser = vi.hoisted(() => vi.fn()); @@ -18,6 +18,15 @@ vi.mock("./interactions.js", () => ({ })); describe("mattermost monitor resources", () => { + beforeEach(() => { + vi.resetModules(); + fetchMattermostChannel.mockReset(); + fetchMattermostUser.mockReset(); + sendMattermostTyping.mockReset(); + updateMattermostPost.mockReset(); + buildButtonProps.mockReset(); + }); + it("downloads media, preserves auth headers, and infers media kind", async () => { const fetchRemoteMedia = vi.fn(async () => ({ buffer: new Uint8Array([1, 2, 3]), diff --git a/extensions/mattermost/src/mattermost/monitor-slash.test.ts b/extensions/mattermost/src/mattermost/monitor-slash.test.ts index c99298e4a55..9d440b24a5d 100644 --- a/extensions/mattermost/src/mattermost/monitor-slash.test.ts +++ b/extensions/mattermost/src/mattermost/monitor-slash.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const listSkillCommandsForAgents = vi.hoisted(() => vi.fn()); const parseStrictPositiveInteger = vi.hoisted(() => vi.fn()); @@ -36,6 +36,19 @@ vi.mock("./slash-state.js", () => ({ })); describe("mattermost monitor slash", () => { + beforeEach(() => { + vi.resetModules(); + listSkillCommandsForAgents.mockReset(); + parseStrictPositiveInteger.mockReset(); + fetchMattermostUserTeams.mockReset(); + normalizeMattermostBaseUrl.mockClear(); + isSlashCommandsEnabled.mockReset(); + registerSlashCommands.mockReset(); + resolveCallbackUrl.mockReset(); + resolveSlashCommandConfig.mockReset(); + activateSlashCommands.mockReset(); + }); + afterEach(() => { vi.unstubAllEnvs(); }); diff --git a/extensions/mattermost/src/mattermost/send.test.ts b/extensions/mattermost/src/mattermost/send.test.ts index 6012c4dff00..93c85041f3e 100644 --- a/extensions/mattermost/src/mattermost/send.test.ts +++ b/extensions/mattermost/src/mattermost/send.test.ts @@ -3,10 +3,14 @@ import { expectProvidedCfgSkipsRuntimeLoad, expectRuntimeCfgFallback, } from "../../../../test/helpers/extensions/send-config.js"; -import { parseMattermostTarget, sendMessageMattermost } from "./send.js"; -import { resetMattermostOpaqueTargetCacheForTests } from "./target-resolution.js"; -type SendMessageMattermostOptions = NonNullable[2]>; +let parseMattermostTarget: typeof import("./send.js").parseMattermostTarget; +let sendMessageMattermost: typeof import("./send.js").sendMessageMattermost; +let resetMattermostOpaqueTargetCacheForTests: typeof import("./target-resolution.js").resetMattermostOpaqueTargetCacheForTests; + +type SendMessageMattermostOptions = NonNullable< + Parameters[2] +>; const mockState = vi.hoisted(() => ({ loadConfig: vi.fn(() => ({})), @@ -74,7 +78,8 @@ vi.mock("../runtime.js", () => ({ })); describe("sendMessageMattermost", () => { - beforeEach(() => { + beforeEach(async () => { + vi.resetModules(); mockState.loadConfig.mockReset(); mockState.loadConfig.mockReturnValue({}); mockState.resolveMattermostAccount.mockReset(); @@ -95,7 +100,6 @@ describe("sendMessageMattermost", () => { mockState.fetchMattermostUserTeams.mockReset(); mockState.fetchMattermostUserByUsername.mockReset(); mockState.uploadMattermostFile.mockReset(); - resetMattermostOpaqueTargetCacheForTests(); mockState.createMattermostClient.mockReturnValue({}); mockState.createMattermostPost.mockResolvedValue({ id: "post-1" }); mockState.createMattermostDirectChannelWithRetry.mockResolvedValue({ id: "dm-channel-1" }); @@ -103,6 +107,9 @@ describe("sendMessageMattermost", () => { mockState.fetchMattermostUserTeams.mockResolvedValue([{ id: "team-1" }]); mockState.fetchMattermostChannelByName.mockResolvedValue({ id: "town-square" }); mockState.uploadMattermostFile.mockResolvedValue({ id: "file-1" }); + ({ parseMattermostTarget, sendMessageMattermost } = await import("./send.js")); + ({ resetMattermostOpaqueTargetCacheForTests } = await import("./target-resolution.js")); + resetMattermostOpaqueTargetCacheForTests(); }); it("uses provided cfg and skips runtime loadConfig", async () => { diff --git a/extensions/mattermost/src/mattermost/slash-http.send-config.test.ts b/extensions/mattermost/src/mattermost/slash-http.send-config.test.ts index 0a44365f454..fb1fe618d23 100644 --- a/extensions/mattermost/src/mattermost/slash-http.send-config.test.ts +++ b/extensions/mattermost/src/mattermost/slash-http.send-config.test.ts @@ -104,7 +104,7 @@ vi.mock("./slash-commands.js", () => ({ resolveCommandText: mockState.resolveCommandText, })); -import { createSlashCommandHttpHandler } from "./slash-http.js"; +let createSlashCommandHttpHandler: typeof import("./slash-http.js").createSlashCommandHttpHandler; function createRequest(body = "token=valid-token"): IncomingMessage { const req = new PassThrough(); @@ -173,7 +173,8 @@ const accountFixture: ResolvedMattermostAccount = { }; describe("slash-http cfg threading", () => { - beforeEach(() => { + beforeEach(async () => { + vi.resetModules(); mockState.readRequestBodyWithLimit.mockClear(); mockState.parseSlashCommandPayload.mockClear(); mockState.resolveCommandText.mockClear(); @@ -184,6 +185,7 @@ describe("slash-http cfg threading", () => { mockState.fetchMattermostChannel.mockClear(); mockState.sendMessageMattermost.mockClear(); mockState.normalizeMattermostAllowList.mockClear(); + ({ createSlashCommandHttpHandler } = await import("./slash-http.js")); }); it("passes cfg through the no-models slash reply send path", async () => { diff --git a/extensions/mattermost/src/mattermost/target-resolution.test.ts b/extensions/mattermost/src/mattermost/target-resolution.test.ts index 3e22f29f3dd..cc39e33c3ca 100644 --- a/extensions/mattermost/src/mattermost/target-resolution.test.ts +++ b/extensions/mattermost/src/mattermost/target-resolution.test.ts @@ -17,6 +17,7 @@ vi.mock("./client.js", () => ({ describe("mattermost target resolution", () => { beforeEach(() => { + vi.resetModules(); resolveMattermostAccount.mockReset(); createMattermostClient.mockReset(); fetchMattermostUser.mockReset(); diff --git a/extensions/slack/src/channel.test.ts b/extensions/slack/src/channel.test.ts index 4a52bf2c549..bf6aaecd81a 100644 --- a/extensions/slack/src/channel.test.ts +++ b/extensions/slack/src/channel.test.ts @@ -1,22 +1,23 @@ import { Type } from "@sinclair/typebox"; -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; import { createRuntimeEnv } from "../../../test/helpers/extensions/runtime-env.js"; +import { slackPlugin } from "./channel.js"; import { slackOutbound } from "./outbound-adapter.js"; import type { OpenClawConfig } from "./runtime-api.js"; +import { setSlackRuntime } from "./runtime.js"; const handleSlackActionMock = vi.fn(); -vi.mock("./runtime.js", () => ({ - getSlackRuntime: () => ({ +beforeEach(async () => { + handleSlackActionMock.mockReset(); + setSlackRuntime({ channel: { slack: { handleSlackAction: handleSlackActionMock, }, }, - }), -})); - -import { slackPlugin } from "./channel.js"; + } as never); +}); async function getSlackConfiguredState(cfg: OpenClawConfig) { const account = slackPlugin.config.resolveAccount(cfg, "default");