From 6366010884ac84164bfbcb5b5ae04718de17923b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 4 Apr 2026 00:03:24 +0900 Subject: [PATCH] fix(ci): route extension test helpers through public sdk seams --- extensions/browser/test-support.ts | 13 +++++++++---- extensions/discord/src/api.test.ts | 2 +- extensions/discord/src/chunk.test.ts | 2 +- extensions/discord/src/resolve-channels.test.ts | 2 +- extensions/discord/src/resolve-users.test.ts | 2 +- .../media-understanding-provider.video.test.ts | 2 +- extensions/google/web-search-provider.test.ts | 2 +- extensions/kilocode/onboard.test.ts | 2 +- .../moonshot/src/kimi-web-search-provider.test.ts | 2 +- extensions/msteams/src/graph-upload.test.ts | 2 +- .../src/perplexity-web-search-provider.test.ts | 2 +- extensions/slack/src/monitor/media.test.ts | 5 +---- extensions/telegram/src/account-inspect.test.ts | 2 +- extensions/telegram/src/accounts.test.ts | 2 +- extensions/telegram/src/action-runtime.test.ts | 2 +- .../telegram/src/bot.create-telegram-bot.test.ts | 2 +- extensions/telegram/src/probe.test.ts | 2 +- extensions/telegram/src/thread-bindings.test.ts | 2 +- .../whatsapp/src/accounts.whatsapp-auth.test.ts | 2 +- ...eb-auto-reply.connection-and-logging.e2e.test.ts | 2 +- extensions/whatsapp/src/media.test.ts | 2 +- extensions/xai/code-execution.test.ts | 2 +- extensions/xai/web-search.test.ts | 2 +- extensions/xai/x-search.test.ts | 2 +- extensions/zalouser/src/channel.setup.test.ts | 2 +- src/plugin-sdk/browser-support.ts | 4 ++++ src/plugin-sdk/testing.ts | 9 +++++++++ 27 files changed, 46 insertions(+), 31 deletions(-) diff --git a/extensions/browser/test-support.ts b/extensions/browser/test-support.ts index 6e38705d738..bc99fc35948 100644 --- a/extensions/browser/test-support.ts +++ b/extensions/browser/test-support.ts @@ -4,8 +4,13 @@ export { type CliRuntimeCapture, } from "../../src/cli/test-runtime-capture.js"; export { isLiveTestEnabled } from "../../src/agents/live-test-helpers.js"; -export { type OpenClawConfig } from "openclaw/plugin-sdk/browser-support"; +export { + createTempHomeEnv, + type FetchMock, + type OpenClawConfig, + type TempHomeEnv, + withEnv, + withEnvAsync, + withFetchPreconnect, +} from "openclaw/plugin-sdk/browser-support"; export { expectGeneratedTokenPersistedToGatewayAuth } from "../../src/test-utils/auth-token-assertions.js"; -export { withEnv, withEnvAsync } from "../../test/helpers/plugins/env.ts"; -export { withFetchPreconnect, type FetchMock } from "../../test/helpers/plugins/fetch-mock.ts"; -export { createTempHomeEnv, type TempHomeEnv } from "../../test/helpers/plugins/temp-home.ts"; diff --git a/extensions/discord/src/api.test.ts b/extensions/discord/src/api.test.ts index 6e2453dec7c..8ccd840e382 100644 --- a/extensions/discord/src/api.test.ts +++ b/extensions/discord/src/api.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../../test/helpers/plugins/fetch-mock.js"; import { fetchDiscord } from "./api.js"; import { jsonResponse } from "./test-http-helpers.js"; diff --git a/extensions/discord/src/chunk.test.ts b/extensions/discord/src/chunk.test.ts index 70eaf2486bd..a8cee387fa9 100644 --- a/extensions/discord/src/chunk.test.ts +++ b/extensions/discord/src/chunk.test.ts @@ -1,5 +1,5 @@ +import { countLines, hasBalancedFences } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { countLines, hasBalancedFences } from "../../../test/helpers/plugins/chunk.js"; import { chunkDiscordText, chunkDiscordTextWithMode } from "./chunk.js"; describe("chunkDiscordText", () => { diff --git a/extensions/discord/src/resolve-channels.test.ts b/extensions/discord/src/resolve-channels.test.ts index c18a5935bc2..ec98a1bc19d 100644 --- a/extensions/discord/src/resolve-channels.test.ts +++ b/extensions/discord/src/resolve-channels.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withFetchPreconnect } from "../../../test/helpers/plugins/fetch-mock.js"; import { resolveDiscordChannelAllowlist } from "./resolve-channels.js"; import { jsonResponse, urlToString } from "./test-http-helpers.js"; diff --git a/extensions/discord/src/resolve-users.test.ts b/extensions/discord/src/resolve-users.test.ts index 8ffd0762d94..78666186ddb 100644 --- a/extensions/discord/src/resolve-users.test.ts +++ b/extensions/discord/src/resolve-users.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withFetchPreconnect } from "../../../test/helpers/plugins/fetch-mock.js"; import { resolveDiscordUserAllowlist } from "./resolve-users.js"; import { jsonResponse, urlToString } from "./test-http-helpers.js"; diff --git a/extensions/google/media-understanding-provider.video.test.ts b/extensions/google/media-understanding-provider.video.test.ts index a650e6680fc..d4d903cc1b2 100644 --- a/extensions/google/media-understanding-provider.video.test.ts +++ b/extensions/google/media-understanding-provider.video.test.ts @@ -1,6 +1,6 @@ import * as ssrf from "openclaw/plugin-sdk/infra-runtime"; +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../test/helpers/plugins/fetch-mock.js"; import { createRequestCaptureJsonFetch } from "../../test/helpers/plugins/media-understanding.js"; import { describeGeminiVideo } from "./media-understanding-provider.js"; diff --git a/extensions/google/web-search-provider.test.ts b/extensions/google/web-search-provider.test.ts index 0b62e1a7bd1..c81d99ce68a 100644 --- a/extensions/google/web-search-provider.test.ts +++ b/extensions/google/web-search-provider.test.ts @@ -1,6 +1,6 @@ +import { withEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../../src/config/config.js"; -import { withEnv } from "../../test/helpers/plugins/env.js"; import { __testing, createGeminiWebSearchProvider } from "./src/gemini-web-search-provider.js"; describe("google web search provider", () => { diff --git a/extensions/kilocode/onboard.test.ts b/extensions/kilocode/onboard.test.ts index 8deb13b62e5..2bfe2c55492 100644 --- a/extensions/kilocode/onboard.test.ts +++ b/extensions/kilocode/onboard.test.ts @@ -14,8 +14,8 @@ import { resolveEnvApiKey, } from "openclaw/plugin-sdk/provider-auth-runtime"; import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard"; +import { captureEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { captureEnv } from "../../test/helpers/plugins/env.js"; import { applyKilocodeProviderConfig, applyKilocodeConfig, diff --git a/extensions/moonshot/src/kimi-web-search-provider.test.ts b/extensions/moonshot/src/kimi-web-search-provider.test.ts index cb748366a71..b4ab61af99a 100644 --- a/extensions/moonshot/src/kimi-web-search-provider.test.ts +++ b/extensions/moonshot/src/kimi-web-search-provider.test.ts @@ -1,5 +1,5 @@ +import { withEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withEnv } from "../../../test/helpers/plugins/env.js"; import { __testing } from "./kimi-web-search-provider.js"; const kimiApiKeyEnv = ["KIMI_API", "KEY"].join("_"); diff --git a/extensions/msteams/src/graph-upload.test.ts b/extensions/msteams/src/graph-upload.test.ts index af7b6eeb39f..d76103d689c 100644 --- a/extensions/msteams/src/graph-upload.test.ts +++ b/extensions/msteams/src/graph-upload.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../../test/helpers/plugins/fetch-mock.js"; import { buildTeamsFileInfoCard } from "./graph-chat.js"; import { resolveGraphChatId, uploadToOneDrive, uploadToSharePoint } from "./graph-upload.js"; diff --git a/extensions/perplexity/src/perplexity-web-search-provider.test.ts b/extensions/perplexity/src/perplexity-web-search-provider.test.ts index 35ff72302dc..d507f605769 100644 --- a/extensions/perplexity/src/perplexity-web-search-provider.test.ts +++ b/extensions/perplexity/src/perplexity-web-search-provider.test.ts @@ -1,5 +1,5 @@ +import { withEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withEnv } from "../../../test/helpers/plugins/env.js"; import { __testing } from "./perplexity-web-search-provider.js"; const openRouterApiKeyEnv = ["OPENROUTER_API", "KEY"].join("_"); diff --git a/extensions/slack/src/monitor/media.test.ts b/extensions/slack/src/monitor/media.test.ts index 35d52eb0ae9..072200ee545 100644 --- a/extensions/slack/src/monitor/media.test.ts +++ b/extensions/slack/src/monitor/media.test.ts @@ -2,12 +2,9 @@ import * as ssrf from "openclaw/plugin-sdk/infra-runtime"; import * as mediaFetch from "openclaw/plugin-sdk/media-runtime"; import type { SavedMedia } from "openclaw/plugin-sdk/media-runtime"; import * as mediaStore from "openclaw/plugin-sdk/media-runtime"; +import { type FetchMock, withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { mockPinnedHostnameResolution } from "../../../../src/test-helpers/ssrf.js"; -import { - type FetchMock, - withFetchPreconnect, -} from "../../../../test/helpers/plugins/fetch-mock.js"; import { fetchWithSlackAuth, resolveSlackAttachmentContent, diff --git a/extensions/telegram/src/account-inspect.test.ts b/extensions/telegram/src/account-inspect.test.ts index abb578bfcca..55107afec08 100644 --- a/extensions/telegram/src/account-inspect.test.ts +++ b/extensions/telegram/src/account-inspect.test.ts @@ -2,8 +2,8 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { withEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withEnv } from "../../../test/helpers/plugins/env.js"; import { inspectTelegramAccount } from "./account-inspect.js"; describe("inspectTelegramAccount SecretRef resolution", () => { diff --git a/extensions/telegram/src/accounts.test.ts b/extensions/telegram/src/accounts.test.ts index 6d94d71e771..09729e4e9c4 100644 --- a/extensions/telegram/src/accounts.test.ts +++ b/extensions/telegram/src/accounts.test.ts @@ -1,7 +1,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import * as runtimeEnvModule from "openclaw/plugin-sdk/runtime-env"; +import { withEnv } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { withEnv } from "../../../test/helpers/plugins/env.js"; import { listTelegramAccountIds, resolveTelegramMediaRuntimeOptions, diff --git a/extensions/telegram/src/action-runtime.test.ts b/extensions/telegram/src/action-runtime.test.ts index e99020da101..ff9c2f178db 100644 --- a/extensions/telegram/src/action-runtime.test.ts +++ b/extensions/telegram/src/action-runtime.test.ts @@ -1,6 +1,6 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { captureEnv } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { captureEnv } from "../../../test/helpers/plugins/env.js"; import { handleTelegramAction, readTelegramButtons, diff --git a/extensions/telegram/src/bot.create-telegram-bot.test.ts b/extensions/telegram/src/bot.create-telegram-bot.test.ts index e436d46d8e5..8b1f6a14044 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.test.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.test.ts @@ -1,7 +1,7 @@ import type { GetReplyOptions, MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { withEnvAsync } from "openclaw/plugin-sdk/testing"; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { escapeRegExp, formatEnvelopeTimestamp } from "../../../test/helpers/envelope-timestamp.js"; -import { withEnvAsync } from "../../../test/helpers/plugins/env.js"; const harness = await import("./bot.create-telegram-bot.test-harness.js"); const EYES_EMOJI = "\u{1F440}"; const { diff --git a/extensions/telegram/src/probe.test.ts b/extensions/telegram/src/probe.test.ts index b444c82c2e5..b5619fa48ef 100644 --- a/extensions/telegram/src/probe.test.ts +++ b/extensions/telegram/src/probe.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeAll, beforeEach, type Mock, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../../test/helpers/plugins/fetch-mock.js"; const resolveTelegramFetch = vi.hoisted(() => vi.fn()); const makeProxyFetch = vi.hoisted(() => vi.fn()); diff --git a/extensions/telegram/src/thread-bindings.test.ts b/extensions/telegram/src/thread-bindings.test.ts index 90b704c0b51..7d6803d28d9 100644 --- a/extensions/telegram/src/thread-bindings.test.ts +++ b/extensions/telegram/src/thread-bindings.test.ts @@ -3,9 +3,9 @@ import os from "node:os"; import path from "node:path"; import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; +import { loadBundledPluginTestApiSync } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { importFreshModule } from "../../../test/helpers/import-fresh.js"; -import { loadBundledPluginTestApiSync } from "../../../test/helpers/plugins/bundled-plugin-public-surface.js"; import { __testing, createTelegramThreadBindingManager, diff --git a/extensions/whatsapp/src/accounts.whatsapp-auth.test.ts b/extensions/whatsapp/src/accounts.whatsapp-auth.test.ts index b82ad57985c..d676c4ed7aa 100644 --- a/extensions/whatsapp/src/accounts.whatsapp-auth.test.ts +++ b/extensions/whatsapp/src/accounts.whatsapp-auth.test.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; +import { captureEnv } from "openclaw/plugin-sdk/testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { captureEnv } from "../../../test/helpers/plugins/env.js"; import { hasAnyWhatsAppAuth, listWhatsAppAuthDirs } from "./accounts.js"; describe("hasAnyWhatsAppAuth", () => { diff --git a/extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts b/extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts index 439dd7f51cb..cbd9d07e70c 100644 --- a/extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +++ b/extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts @@ -3,9 +3,9 @@ import crypto from "node:crypto"; import fs from "node:fs/promises"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { setLoggerOverride } from "openclaw/plugin-sdk/runtime-env"; +import { withEnvAsync } from "openclaw/plugin-sdk/testing"; import { beforeAll, describe, expect, it, vi } from "vitest"; import { escapeRegExp, formatEnvelopeTimestamp } from "../../../test/helpers/envelope-timestamp.js"; -import { withEnvAsync } from "../../../test/helpers/plugins/env.js"; import { createWebInboundDeliverySpies, createMockWebListener, diff --git a/extensions/whatsapp/src/media.test.ts b/extensions/whatsapp/src/media.test.ts index ce210122f3a..8606d26f055 100644 --- a/extensions/whatsapp/src/media.test.ts +++ b/extensions/whatsapp/src/media.test.ts @@ -4,10 +4,10 @@ import path from "node:path"; import { optimizeImageToPng } from "openclaw/plugin-sdk/media-runtime"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path"; +import { captureEnv } from "openclaw/plugin-sdk/testing"; import sharp from "sharp"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { mockPinnedHostnameResolution } from "../../../src/test-helpers/ssrf.js"; -import { captureEnv } from "../../../test/helpers/plugins/env.js"; import { sendVoiceMessageDiscord } from "../../discord/src/send.js"; import { LocalMediaAccessError, diff --git a/extensions/xai/code-execution.test.ts b/extensions/xai/code-execution.test.ts index e621e551377..4810bebcc8a 100644 --- a/extensions/xai/code-execution.test.ts +++ b/extensions/xai/code-execution.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../test/helpers/plugins/fetch-mock.js"; import { createCodeExecutionTool } from "./code-execution.js"; function installCodeExecutionFetch(payload?: Record) { diff --git a/extensions/xai/web-search.test.ts b/extensions/xai/web-search.test.ts index 3c70e24ec0c..9681a6fdecf 100644 --- a/extensions/xai/web-search.test.ts +++ b/extensions/xai/web-search.test.ts @@ -1,8 +1,8 @@ import { NON_ENV_SECRETREF_MARKER } from "openclaw/plugin-sdk/provider-auth-runtime"; import { createNonExitingRuntime } from "openclaw/plugin-sdk/runtime-env"; +import { withEnv } from "openclaw/plugin-sdk/testing"; import { describe, expect, it, vi } from "vitest"; import { capturePluginRegistration } from "../../src/plugins/captured-registration.js"; -import { withEnv } from "../../test/helpers/plugins/env.js"; import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js"; import xaiPlugin from "./index.js"; import { resolveXaiCatalogEntry } from "./model-definitions.js"; diff --git a/extensions/xai/x-search.test.ts b/extensions/xai/x-search.test.ts index 74f4634cc20..f6e57052abe 100644 --- a/extensions/xai/x-search.test.ts +++ b/extensions/xai/x-search.test.ts @@ -1,5 +1,5 @@ +import { withFetchPreconnect } from "openclaw/plugin-sdk/testing"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../test/helpers/plugins/fetch-mock.js"; import { createXSearchTool } from "./x-search.js"; function installXSearchFetch(payload?: Record) { diff --git a/extensions/zalouser/src/channel.setup.test.ts b/extensions/zalouser/src/channel.setup.test.ts index 453c0aa63da..4821700cc63 100644 --- a/extensions/zalouser/src/channel.setup.test.ts +++ b/extensions/zalouser/src/channel.setup.test.ts @@ -1,8 +1,8 @@ import { mkdtemp, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; +import { withEnvAsync } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; -import { withEnvAsync } from "../../../test/helpers/plugins/env.js"; import { createPluginSetupWizardStatus } from "../../../test/helpers/plugins/setup-wizard.js"; import "./zalo-js.test-mocks.js"; import { zalouserSetupPlugin } from "./channel.setup.js"; diff --git a/src/plugin-sdk/browser-support.ts b/src/plugin-sdk/browser-support.ts index 2a053f8f097..cfdb5cb25e0 100644 --- a/src/plugin-sdk/browser-support.ts +++ b/src/plugin-sdk/browser-support.ts @@ -88,5 +88,9 @@ export { generateSecureToken } from "../infra/secure-random.js"; export { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js"; export { rawDataToString } from "../infra/ws.js"; export { runExec } from "../process/exec.js"; +export { captureEnv, withEnv, withEnvAsync } from "../test-utils/env.js"; export { withFetchPreconnect } from "../test-utils/fetch-mock.js"; +export type { FetchMock } from "../test-utils/fetch-mock.js"; +export { createTempHomeEnv } from "../test-utils/temp-home.js"; +export type { TempHomeEnv } from "../test-utils/temp-home.js"; export type { MockFn } from "../test-utils/vitest-mock-fn.js"; diff --git a/src/plugin-sdk/testing.ts b/src/plugin-sdk/testing.ts index 49dcc98a507..150846ff86f 100644 --- a/src/plugin-sdk/testing.ts +++ b/src/plugin-sdk/testing.ts @@ -55,3 +55,12 @@ export { createWindowsCmdShimFixture } from "../test-helpers/windows-cmd-shim.js export { installCommonResolveTargetErrorCases } from "../test-helpers/resolve-target-error-cases.js"; export { sanitizeTerminalText } from "../terminal/safe-text.js"; export { withStateDirEnv } from "../test-helpers/state-dir-env.js"; +export { countLines, hasBalancedFences } from "../test-utils/chunk-test-helpers.js"; +export { + loadBundledPluginPublicSurfaceSync, + loadBundledPluginTestApiSync, + resolveRelativeBundledPluginPublicModuleId, +} from "../test-utils/bundled-plugin-public-surface.js"; +export { captureEnv, withEnv, withEnvAsync } from "../test-utils/env.js"; +export { withFetchPreconnect, type FetchMock } from "../test-utils/fetch-mock.js"; +export { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";