perf: split more scoped vitest lanes

This commit is contained in:
Peter Steinberger
2026-04-04 05:25:04 +01:00
parent 64b971b2b0
commit c7cb43cac9
37 changed files with 1107 additions and 49 deletions

View File

@@ -1091,7 +1091,7 @@
"runtime-sidecars:gen": "node --import tsx scripts/generate-runtime-sidecar-paths-baseline.ts --write",
"stage:bundled-plugin-runtime-deps": "node scripts/stage-bundled-plugin-runtime-deps.mjs",
"start": "node scripts/run-node.mjs",
"test": "vitest run --config vitest.config.ts",
"test": "node scripts/test-projects.mjs",
"test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
"test:auth:compat": "vitest run --config vitest.gateway.config.ts src/gateway/server.auth.compat-baseline.test.ts src/gateway/client.test.ts src/gateway/reconnect-gating.test.ts src/gateway/protocol/connect-error-details.test.ts",
"test:build:singleton": "node scripts/test-built-plugin-singleton.mjs",
@@ -1135,7 +1135,7 @@
"test:live": "node scripts/test-live.mjs",
"test:live:gateway-profiles": "node scripts/test-live.mjs -- src/gateway/gateway-models.profiles.live.test.ts",
"test:live:models-profiles": "node scripts/test-live.mjs -- src/agents/models.profiles.live.test.ts",
"test:max": "OPENCLAW_VITEST_MAX_WORKERS=8 vitest run --config vitest.config.ts",
"test:max": "OPENCLAW_VITEST_MAX_WORKERS=8 node scripts/test-projects.mjs",
"test:parallels:linux": "bash scripts/e2e/parallels-linux-smoke.sh",
"test:parallels:macos": "bash scripts/e2e/parallels-macos-smoke.sh",
"test:parallels:npm-update": "bash scripts/e2e/parallels-npm-update-smoke.sh",
@@ -1147,7 +1147,7 @@
"test:perf:profile:main": "node scripts/run-vitest-profile.mjs main",
"test:perf:profile:runner": "node scripts/run-vitest-profile.mjs runner",
"test:sectriage": "pnpm exec vitest run --config vitest.gateway.config.ts && vitest run --config vitest.unit.config.ts --exclude src/daemon/launchd.integration.test.ts --exclude src/process/exec.test.ts",
"test:serial": "OPENCLAW_VITEST_MAX_WORKERS=1 vitest run --config vitest.config.ts",
"test:serial": "OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/test-projects.mjs",
"test:startup:bench": "node --import tsx scripts/bench-cli-startup.ts",
"test:startup:bench:check": "node scripts/test-cli-startup-bench-budget.mjs",
"test:startup:bench:save": "node --import tsx scripts/bench-cli-startup.ts --preset all --runs 5 --warmup 1 --output .artifacts/cli-startup-bench-all.json",
@@ -1156,7 +1156,7 @@
"test:startup:memory": "node scripts/check-cli-startup-memory.mjs",
"test:ui": "pnpm lint:ui:no-raw-window-open && pnpm --dir ui test",
"test:voicecall:closedloop": "node scripts/test-voicecall-closedloop.mjs",
"test:watch": "vitest --config vitest.config.ts",
"test:watch": "node scripts/test-projects.mjs --watch",
"ts-topology": "node --import tsx scripts/ts-topology.ts",
"tsgo": "node scripts/run-tsgo.mjs",
"tui": "node scripts/run-node.mjs tui",

View File

@@ -1,7 +1,14 @@
import fs from "node:fs";
import path from "node:path";
import { channelTestRoots } from "../../vitest.channel-paths.mjs";
import { isAcpxExtensionRoot } from "../../vitest.extension-acpx-paths.mjs";
import { isBlueBubblesExtensionRoot } from "../../vitest.extension-bluebubbles-paths.mjs";
import { isDiffsExtensionRoot } from "../../vitest.extension-diffs-paths.mjs";
import { isMatrixExtensionRoot } from "../../vitest.extension-matrix-paths.mjs";
import { isMemoryExtensionRoot } from "../../vitest.extension-memory-paths.mjs";
import { isMessagingExtensionRoot } from "../../vitest.extension-messaging-paths.mjs";
import { isProviderExtensionRoot } from "../../vitest.extension-provider-paths.mjs";
import { isTelegramExtensionRoot } from "../../vitest.extension-telegram-paths.mjs";
import { BUNDLED_PLUGIN_PATH_PREFIX, BUNDLED_PLUGIN_ROOT_DIR } from "./bundled-plugin-paths.mjs";
import { listAvailableExtensionIds } from "./changed-extensions.mjs";
@@ -90,12 +97,33 @@ export function resolveExtensionTestPlan(params = {}) {
}
const usesChannelConfig = roots.some((root) => channelTestRoots.includes(root));
const usesAcpxConfig = roots.some((root) => isAcpxExtensionRoot(root));
const usesDiffsConfig = roots.some((root) => isDiffsExtensionRoot(root));
const usesBlueBubblesConfig = roots.some((root) => isBlueBubblesExtensionRoot(root));
const usesTelegramConfig = roots.some((root) => isTelegramExtensionRoot(root));
const usesMatrixConfig = roots.some((root) => isMatrixExtensionRoot(root));
const usesMemoryConfig = roots.some((root) => isMemoryExtensionRoot(root));
const usesMessagingConfig = roots.some((root) => isMessagingExtensionRoot(root));
const usesProviderConfig = roots.some((root) => isProviderExtensionRoot(root));
const config = usesChannelConfig
? "vitest.extension-channels.config.ts"
: usesProviderConfig
? "vitest.extension-providers.config.ts"
: "vitest.extensions.config.ts";
: usesAcpxConfig
? "vitest.extension-acpx.config.ts"
: usesDiffsConfig
? "vitest.extension-diffs.config.ts"
: usesBlueBubblesConfig
? "vitest.extension-bluebubbles.config.ts"
: usesMatrixConfig
? "vitest.extension-matrix.config.ts"
: usesTelegramConfig
? "vitest.extension-telegram.config.ts"
: usesMemoryConfig
? "vitest.extension-memory.config.ts"
: usesMessagingConfig
? "vitest.extension-messaging.config.ts"
: usesProviderConfig
? "vitest.extension-providers.config.ts"
: "vitest.extensions.config.ts";
const testFileCount = roots.reduce(
(sum, root) => sum + countTestFiles(path.join(repoRoot, root)),
0,

View File

@@ -2,7 +2,14 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { isChannelSurfaceTestFile } from "../vitest.channel-paths.mjs";
import { isAcpxExtensionRoot } from "../vitest.extension-acpx-paths.mjs";
import { isBlueBubblesExtensionRoot } from "../vitest.extension-bluebubbles-paths.mjs";
import { isDiffsExtensionRoot } from "../vitest.extension-diffs-paths.mjs";
import { isMatrixExtensionRoot } from "../vitest.extension-matrix-paths.mjs";
import { isMemoryExtensionRoot } from "../vitest.extension-memory-paths.mjs";
import { isMessagingExtensionRoot } from "../vitest.extension-messaging-paths.mjs";
import { isProviderExtensionRoot } from "../vitest.extension-provider-paths.mjs";
import { isTelegramExtensionRoot } from "../vitest.extension-telegram-paths.mjs";
import { isBoundaryTestFile, isBundledPluginDependentUnitTestFile } from "../vitest.unit-paths.mjs";
const DEFAULT_VITEST_CONFIG = "vitest.unit.config.ts";
@@ -12,14 +19,31 @@ const AUTO_REPLY_VITEST_CONFIG = "vitest.auto-reply.config.ts";
const BOUNDARY_VITEST_CONFIG = "vitest.boundary.config.ts";
const BUNDLED_VITEST_CONFIG = "vitest.bundled.config.ts";
const CHANNEL_VITEST_CONFIG = "vitest.channels.config.ts";
const CLI_VITEST_CONFIG = "vitest.cli.config.ts";
const COMMANDS_VITEST_CONFIG = "vitest.commands.config.ts";
const CONTRACTS_VITEST_CONFIG = "vitest.contracts.config.ts";
const CRON_VITEST_CONFIG = "vitest.cron.config.ts";
const DAEMON_VITEST_CONFIG = "vitest.daemon.config.ts";
const E2E_VITEST_CONFIG = "vitest.e2e.config.ts";
const EXTENSION_ACPX_VITEST_CONFIG = "vitest.extension-acpx.config.ts";
const EXTENSION_BLUEBUBBLES_VITEST_CONFIG = "vitest.extension-bluebubbles.config.ts";
const EXTENSION_CHANNELS_VITEST_CONFIG = "vitest.extension-channels.config.ts";
const EXTENSION_DIFFS_VITEST_CONFIG = "vitest.extension-diffs.config.ts";
const EXTENSION_MATRIX_VITEST_CONFIG = "vitest.extension-matrix.config.ts";
const EXTENSION_MEMORY_VITEST_CONFIG = "vitest.extension-memory.config.ts";
const EXTENSION_MESSAGING_VITEST_CONFIG = "vitest.extension-messaging.config.ts";
const EXTENSION_PROVIDERS_VITEST_CONFIG = "vitest.extension-providers.config.ts";
const EXTENSION_TELEGRAM_VITEST_CONFIG = "vitest.extension-telegram.config.ts";
const EXTENSIONS_VITEST_CONFIG = "vitest.extensions.config.ts";
const GATEWAY_VITEST_CONFIG = "vitest.gateway.config.ts";
const INFRA_VITEST_CONFIG = "vitest.infra.config.ts";
const MEDIA_VITEST_CONFIG = "vitest.media.config.ts";
const MEDIA_UNDERSTANDING_VITEST_CONFIG = "vitest.media-understanding.config.ts";
const PLUGIN_SDK_VITEST_CONFIG = "vitest.plugin-sdk.config.ts";
const PLUGINS_VITEST_CONFIG = "vitest.plugins.config.ts";
const RUNTIME_CONFIG_VITEST_CONFIG = "vitest.runtime-config.config.ts";
const SECRETS_VITEST_CONFIG = "vitest.secrets.config.ts";
const SHARED_CORE_VITEST_CONFIG = "vitest.shared-core.config.ts";
const TOOLING_VITEST_CONFIG = "vitest.tooling.config.ts";
const UI_VITEST_CONFIG = "vitest.ui.config.ts";
const INCLUDE_FILE_ENV_KEY = "OPENCLAW_VITEST_INCLUDE_FILE";
@@ -85,6 +109,27 @@ function classifyTarget(arg, cwd) {
if (isChannelSurfaceTestFile(relative)) {
return "extensionChannel";
}
if (isAcpxExtensionRoot(extensionRoot)) {
return "extensionAcpx";
}
if (isDiffsExtensionRoot(extensionRoot)) {
return "extensionDiffs";
}
if (isBlueBubblesExtensionRoot(extensionRoot)) {
return "extensionBlueBubbles";
}
if (isTelegramExtensionRoot(extensionRoot)) {
return "extensionTelegram";
}
if (isMatrixExtensionRoot(extensionRoot)) {
return "extensionMatrix";
}
if (isMemoryExtensionRoot(extensionRoot)) {
return "extensionMemory";
}
if (isMessagingExtensionRoot(extensionRoot)) {
return "extensionMessaging";
}
return isProviderExtensionRoot(extensionRoot) ? "extensionProvider" : "extension";
}
if (isChannelSurfaceTestFile(relative)) {
@@ -110,15 +155,45 @@ function classifyTarget(arg, cwd) {
if (isBundledPluginDependentUnitTestFile(relative)) {
return "bundled";
}
if (relative.startsWith("src/channels/")) {
return "channel";
}
if (relative.startsWith("src/gateway/")) {
return "gateway";
}
if (relative.startsWith("src/infra/")) {
return "infra";
}
if (relative.startsWith("src/config/")) {
return "runtimeConfig";
}
if (relative.startsWith("src/cron/")) {
return "cron";
}
if (relative.startsWith("src/daemon/")) {
return "daemon";
}
if (relative.startsWith("src/media-understanding/")) {
return "mediaUnderstanding";
}
if (relative.startsWith("src/media/")) {
return "media";
}
if (relative.startsWith("src/plugin-sdk/")) {
return "pluginSdk";
}
if (relative.startsWith("src/secrets/")) {
return "secrets";
}
if (relative.startsWith("src/shared/")) {
return "sharedCore";
}
if (relative.startsWith("src/acp/")) {
return "acp";
}
if (relative.startsWith("src/cli/")) {
return "cli";
}
if (relative.startsWith("src/commands/")) {
return "command";
}
@@ -128,6 +203,9 @@ function classifyTarget(arg, cwd) {
if (relative.startsWith("src/agents/")) {
return "agent";
}
if (relative.startsWith("src/plugins/")) {
return "plugin";
}
if (relative.startsWith("ui/src/ui/")) {
return "ui";
}
@@ -203,13 +281,30 @@ export function buildVitestRunPlans(args, cwd = process.cwd()) {
"bundled",
"gateway",
"infra",
"runtimeConfig",
"cron",
"daemon",
"media",
"pluginSdk",
"secrets",
"sharedCore",
"mediaUnderstanding",
"acp",
"cli",
"command",
"autoReply",
"agent",
"plugin",
"ui",
"e2e",
"extensionAcpx",
"extensionDiffs",
"extensionBlueBubbles",
"extensionChannel",
"extensionTelegram",
"extensionMatrix",
"extensionMemory",
"extensionMessaging",
"extensionProvider",
"channel",
"extension",
@@ -233,27 +328,61 @@ export function buildVitestRunPlans(args, cwd = process.cwd()) {
? GATEWAY_VITEST_CONFIG
: kind === "infra"
? INFRA_VITEST_CONFIG
: kind === "acp"
? ACP_VITEST_CONFIG
: kind === "command"
? COMMANDS_VITEST_CONFIG
: kind === "autoReply"
? AUTO_REPLY_VITEST_CONFIG
: kind === "agent"
? AGENTS_VITEST_CONFIG
: kind === "ui"
? UI_VITEST_CONFIG
: kind === "e2e"
? E2E_VITEST_CONFIG
: kind === "extensionChannel"
? EXTENSION_CHANNELS_VITEST_CONFIG
: kind === "extensionProvider"
? EXTENSION_PROVIDERS_VITEST_CONFIG
: kind === "channel"
? CHANNEL_VITEST_CONFIG
: kind === "extension"
? EXTENSIONS_VITEST_CONFIG
: DEFAULT_VITEST_CONFIG;
: kind === "runtimeConfig"
? RUNTIME_CONFIG_VITEST_CONFIG
: kind === "cron"
? CRON_VITEST_CONFIG
: kind === "daemon"
? DAEMON_VITEST_CONFIG
: kind === "media"
? MEDIA_VITEST_CONFIG
: kind === "pluginSdk"
? PLUGIN_SDK_VITEST_CONFIG
: kind === "secrets"
? SECRETS_VITEST_CONFIG
: kind === "sharedCore"
? SHARED_CORE_VITEST_CONFIG
: kind === "mediaUnderstanding"
? MEDIA_UNDERSTANDING_VITEST_CONFIG
: kind === "acp"
? ACP_VITEST_CONFIG
: kind === "cli"
? CLI_VITEST_CONFIG
: kind === "command"
? COMMANDS_VITEST_CONFIG
: kind === "autoReply"
? AUTO_REPLY_VITEST_CONFIG
: kind === "agent"
? AGENTS_VITEST_CONFIG
: kind === "plugin"
? PLUGINS_VITEST_CONFIG
: kind === "ui"
? UI_VITEST_CONFIG
: kind === "e2e"
? E2E_VITEST_CONFIG
: kind === "extensionAcpx"
? EXTENSION_ACPX_VITEST_CONFIG
: kind === "extensionDiffs"
? EXTENSION_DIFFS_VITEST_CONFIG
: kind === "extensionBlueBubbles"
? EXTENSION_BLUEBUBBLES_VITEST_CONFIG
: kind === "extensionChannel"
? EXTENSION_CHANNELS_VITEST_CONFIG
: kind === "extensionTelegram"
? EXTENSION_TELEGRAM_VITEST_CONFIG
: kind === "extensionMatrix"
? EXTENSION_MATRIX_VITEST_CONFIG
: kind === "extensionMemory"
? EXTENSION_MEMORY_VITEST_CONFIG
: kind === "extensionMessaging"
? EXTENSION_MESSAGING_VITEST_CONFIG
: kind === "extensionProvider"
? EXTENSION_PROVIDERS_VITEST_CONFIG
: kind === "channel"
? CHANNEL_VITEST_CONFIG
: kind === "extension"
? EXTENSIONS_VITEST_CONFIG
: DEFAULT_VITEST_CONFIG;
const includePatterns =
kind === "default" || kind === "e2e"
? null

View File

@@ -135,6 +135,94 @@ describe("test-projects args", () => {
]);
});
it("routes runtime config targets to the runtime-config config", () => {
expect(buildVitestRunPlans(["src/config/sessions.test.ts"])).toEqual([
{
config: "vitest.runtime-config.config.ts",
forwardedArgs: [],
includePatterns: ["src/config/sessions.test.ts"],
watchMode: false,
},
]);
});
it("routes cron targets to the cron config", () => {
expect(buildVitestRunPlans(["src/cron/isolated-agent.lane.test.ts"])).toEqual([
{
config: "vitest.cron.config.ts",
forwardedArgs: [],
includePatterns: ["src/cron/isolated-agent.lane.test.ts"],
watchMode: false,
},
]);
});
it("routes daemon targets to the daemon config", () => {
expect(buildVitestRunPlans(["src/daemon/constants.test.ts"])).toEqual([
{
config: "vitest.daemon.config.ts",
forwardedArgs: [],
includePatterns: ["src/daemon/constants.test.ts"],
watchMode: false,
},
]);
});
it("routes media targets to the media config", () => {
expect(buildVitestRunPlans(["src/media/mime.test.ts"])).toEqual([
{
config: "vitest.media.config.ts",
forwardedArgs: [],
includePatterns: ["src/media/mime.test.ts"],
watchMode: false,
},
]);
});
it("routes plugin-sdk targets to the plugin-sdk config", () => {
expect(buildVitestRunPlans(["src/plugin-sdk/provider-stream.test.ts"])).toEqual([
{
config: "vitest.plugin-sdk.config.ts",
forwardedArgs: [],
includePatterns: ["src/plugin-sdk/provider-stream.test.ts"],
watchMode: false,
},
]);
});
it("routes secrets targets to the secrets config", () => {
expect(buildVitestRunPlans(["src/secrets/resolve.test.ts"])).toEqual([
{
config: "vitest.secrets.config.ts",
forwardedArgs: [],
includePatterns: ["src/secrets/resolve.test.ts"],
watchMode: false,
},
]);
});
it("routes shared-core targets to the shared-core config", () => {
expect(buildVitestRunPlans(["src/shared/text-chunking.test.ts"])).toEqual([
{
config: "vitest.shared-core.config.ts",
forwardedArgs: [],
includePatterns: ["src/shared/text-chunking.test.ts"],
watchMode: false,
},
]);
});
it("routes media-understanding targets to the media-understanding config", () => {
expect(buildVitestRunPlans(["src/media-understanding/runtime.test.ts"])).toEqual([
{
config: "vitest.media-understanding.config.ts",
forwardedArgs: [],
includePatterns: ["src/media-understanding/runtime.test.ts"],
watchMode: false,
},
]);
});
it("routes command targets to the commands config", () => {
expect(buildVitestRunPlans(["src/commands/status.summary.test.ts"])).toEqual([
{
@@ -179,6 +267,17 @@ describe("test-projects args", () => {
]);
});
it("routes channel targets to the channels config", () => {
expect(buildVitestRunPlans(["src/channels/ids.test.ts"])).toEqual([
{
config: "vitest.channels.config.ts",
forwardedArgs: [],
includePatterns: ["src/channels/ids.test.ts"],
watchMode: false,
},
]);
});
it("routes infra targets to the infra config", () => {
expect(buildVitestRunPlans(["src/infra/openclaw-root.test.ts"])).toEqual([
{
@@ -210,6 +309,37 @@ describe("test-projects args", () => {
]);
});
it("routes cli targets to the cli config", () => {
expect(buildVitestRunPlans(["src/cli/test-runtime-capture.test.ts"])).toEqual([
{
config: "vitest.cli.config.ts",
forwardedArgs: [],
includePatterns: ["src/cli/test-runtime-capture.test.ts"],
watchMode: false,
},
]);
});
it("routes plugin targets to the plugins config", () => {
expect(buildVitestRunPlans(["src/plugins/loader.test.ts"])).toEqual([
{
config: "vitest.bundled.config.ts",
forwardedArgs: [],
includePatterns: ["src/plugins/loader.test.ts"],
watchMode: false,
},
]);
expect(buildVitestRunPlans(["src/plugins/discovery.test.ts"])).toEqual([
{
config: "vitest.plugins.config.ts",
forwardedArgs: [],
includePatterns: ["src/plugins/discovery.test.ts"],
watchMode: false,
},
]);
});
it("widens non-test helper file targets to sibling tests inside the routed suite", () => {
expect(buildVitestRunPlans(["src/gateway/gateway-connection.test-mocks.ts"])).toEqual([
{
@@ -226,7 +356,7 @@ describe("test-projects args", () => {
buildVitestRunPlans(["extensions/memory-core/src/memory/test-runtime-mocks.ts"]),
).toEqual([
{
config: "vitest.extensions.config.ts",
config: "vitest.extension-memory.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/memory-core/src/memory/**/*.test.ts"],
watchMode: false,
@@ -234,6 +364,61 @@ describe("test-projects args", () => {
]);
});
it("routes telegram extension tests to the telegram config", () => {
expect(buildVitestRunPlans(["extensions/telegram/src/fetch.test.ts"])).toEqual([
{
config: "vitest.extension-telegram.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/telegram/src/fetch.test.ts"],
watchMode: false,
},
]);
});
it("routes matrix extension tests to the matrix config", () => {
expect(buildVitestRunPlans(["extensions/matrix/src/channel.test.ts"])).toEqual([
{
config: "vitest.extension-matrix.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/matrix/src/channel.test.ts"],
watchMode: false,
},
]);
});
it("routes bluebubbles extension tests to the bluebubbles config", () => {
expect(buildVitestRunPlans(["extensions/bluebubbles/src/monitor.test.ts"])).toEqual([
{
config: "vitest.extension-bluebubbles.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/bluebubbles/src/monitor.test.ts"],
watchMode: false,
},
]);
});
it("routes acpx extension tests to the acpx config", () => {
expect(buildVitestRunPlans(["extensions/acpx/src/runtime.test.ts"])).toEqual([
{
config: "vitest.extension-acpx.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/acpx/src/runtime.test.ts"],
watchMode: false,
},
]);
});
it("routes diffs extension tests to the diffs config", () => {
expect(buildVitestRunPlans(["extensions/diffs/src/render.test.ts"])).toEqual([
{
config: "vitest.extension-diffs.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/diffs/src/render.test.ts"],
watchMode: false,
},
]);
});
it("routes ui targets to the ui config", () => {
expect(buildVitestRunPlans(["ui/src/ui/views/channels.test.ts"])).toEqual([
{
@@ -302,6 +487,17 @@ describe("test-projects args", () => {
]);
});
it("routes matrix extension file targets to the matrix config", () => {
expect(buildVitestRunPlans(["extensions/matrix/src/channel.test.ts"])).toEqual([
{
config: "vitest.extension-matrix.config.ts",
forwardedArgs: [],
includePatterns: ["extensions/matrix/src/channel.test.ts"],
watchMode: false,
},
]);
});
it("routes direct provider extension file targets to the extension providers config", () => {
expect(buildVitestRunPlans(["extensions/openai/openai-codex-provider.test.ts"])).toEqual([
{
@@ -334,9 +530,9 @@ describe("test-projects args", () => {
]),
).toEqual([
{
config: "vitest.unit.config.ts",
forwardedArgs: ["-t", "mention", "src/config/config-misc.test.ts"],
includePatterns: null,
config: "vitest.runtime-config.config.ts",
forwardedArgs: ["-t", "mention"],
includePatterns: ["src/config/config-misc.test.ts"],
watchMode: false,
},
{

View File

@@ -43,6 +43,33 @@ describe("scripts/test-extension.mjs", () => {
expect(plan.hasTests).toBe(true);
});
it("resolves bluebubbles onto the bluebubbles vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "bluebubbles", cwd: process.cwd() });
expect(plan.extensionId).toBe("bluebubbles");
expect(plan.config).toBe("vitest.extension-bluebubbles.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("bluebubbles"));
expect(plan.hasTests).toBe(true);
});
it("resolves acpx onto the acpx vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "acpx", cwd: process.cwd() });
expect(plan.extensionId).toBe("acpx");
expect(plan.config).toBe("vitest.extension-acpx.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("acpx"));
expect(plan.hasTests).toBe(true);
});
it("resolves diffs onto the diffs vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "diffs", cwd: process.cwd() });
expect(plan.extensionId).toBe("diffs");
expect(plan.config).toBe("vitest.extension-diffs.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("diffs"));
expect(plan.hasTests).toBe(true);
});
it("resolves provider extensions onto the provider vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "openai", cwd: process.cwd() });
@@ -52,6 +79,33 @@ describe("scripts/test-extension.mjs", () => {
expect(plan.hasTests).toBe(true);
});
it("resolves matrix onto the matrix vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "matrix", cwd: process.cwd() });
expect(plan.extensionId).toBe("matrix");
expect(plan.config).toBe("vitest.extension-matrix.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("matrix"));
expect(plan.hasTests).toBe(true);
});
it("resolves telegram onto the telegram vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "telegram", cwd: process.cwd() });
expect(plan.extensionId).toBe("telegram");
expect(plan.config).toBe("vitest.extension-telegram.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("telegram"));
expect(plan.hasTests).toBe(true);
});
it("resolves memory extensions onto the memory vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "memory-core", cwd: process.cwd() });
expect(plan.extensionId).toBe("memory-core");
expect(plan.config).toBe("vitest.extension-memory.config.ts");
expect(plan.roots).toContain(bundledPluginRoot("memory-core"));
expect(plan.hasTests).toBe(true);
});
it("keeps non-provider extensions on the shared extensions vitest config", () => {
const plan = resolveExtensionTestPlan({ targetArg: "firecrawl", cwd: process.cwd() });
@@ -66,7 +120,7 @@ describe("scripts/test-extension.mjs", () => {
expect(plan.roots).toContain(bundledPluginRoot("line"));
expect(plan.roots).not.toContain("src/line");
expect(plan.config).toBe("vitest.channels.config.ts");
expect(plan.config).toBe("vitest.extension-channels.config.ts");
expect(plan.hasTests).toBe(true);
});
@@ -120,23 +174,81 @@ describe("scripts/test-extension.mjs", () => {
it("batches extensions into config-specific vitest invocations", () => {
const batch = resolveExtensionBatchPlan({
cwd: process.cwd(),
extensionIds: ["slack", "firecrawl", "line", "openai"],
extensionIds: [
"slack",
"firecrawl",
"line",
"openai",
"matrix",
"telegram",
"memory-core",
"bluebubbles",
"acpx",
"diffs",
],
});
expect(batch.extensionIds).toEqual(["firecrawl", "line", "openai", "slack"]);
expect(batch.extensionIds).toEqual([
"acpx",
"bluebubbles",
"diffs",
"firecrawl",
"line",
"matrix",
"memory-core",
"openai",
"slack",
"telegram",
]);
expect(batch.planGroups).toEqual([
{
config: "vitest.channels.config.ts",
config: "vitest.extension-acpx.config.ts",
extensionIds: ["acpx"],
roots: [bundledPluginRoot("acpx")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-bluebubbles.config.ts",
extensionIds: ["bluebubbles"],
roots: [bundledPluginRoot("bluebubbles")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-channels.config.ts",
extensionIds: ["line", "slack"],
roots: [bundledPluginRoot("slack"), bundledPluginRoot("line")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-diffs.config.ts",
extensionIds: ["diffs"],
roots: [bundledPluginRoot("diffs")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-matrix.config.ts",
extensionIds: ["matrix"],
roots: [bundledPluginRoot("matrix")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-memory.config.ts",
extensionIds: ["memory-core"],
roots: [bundledPluginRoot("memory-core")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-providers.config.ts",
extensionIds: ["openai"],
roots: [bundledPluginRoot("openai")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extension-telegram.config.ts",
extensionIds: ["telegram"],
roots: [bundledPluginRoot("telegram")],
testFileCount: expect.any(Number),
},
{
config: "vitest.extensions.config.ts",
extensionIds: ["firecrawl"],

View File

@@ -6,13 +6,30 @@ import { createAcpVitestConfig } from "../vitest.acp.config.ts";
import { createAgentsVitestConfig } from "../vitest.agents.config.ts";
import { createAutoReplyVitestConfig } from "../vitest.auto-reply.config.ts";
import { createChannelsVitestConfig } from "../vitest.channels.config.ts";
import { createCliVitestConfig } from "../vitest.cli.config.ts";
import { createCommandsVitestConfig } from "../vitest.commands.config.ts";
import { createCronVitestConfig } from "../vitest.cron.config.ts";
import { createDaemonVitestConfig } from "../vitest.daemon.config.ts";
import { createExtensionAcpxVitestConfig } from "../vitest.extension-acpx.config.ts";
import { createExtensionBlueBubblesVitestConfig } from "../vitest.extension-bluebubbles.config.ts";
import { createExtensionChannelsVitestConfig } from "../vitest.extension-channels.config.ts";
import { createExtensionDiffsVitestConfig } from "../vitest.extension-diffs.config.ts";
import { createExtensionMatrixVitestConfig } from "../vitest.extension-matrix.config.ts";
import { createExtensionMemoryVitestConfig } from "../vitest.extension-memory.config.ts";
import { createExtensionMessagingVitestConfig } from "../vitest.extension-messaging.config.ts";
import { createExtensionProvidersVitestConfig } from "../vitest.extension-providers.config.ts";
import { createExtensionTelegramVitestConfig } from "../vitest.extension-telegram.config.ts";
import { createExtensionsVitestConfig } from "../vitest.extensions.config.ts";
import { createGatewayVitestConfig } from "../vitest.gateway.config.ts";
import { createInfraVitestConfig } from "../vitest.infra.config.ts";
import { createMediaUnderstandingVitestConfig } from "../vitest.media-understanding.config.ts";
import { createMediaVitestConfig } from "../vitest.media.config.ts";
import { createPluginSdkVitestConfig } from "../vitest.plugin-sdk.config.ts";
import { createPluginsVitestConfig } from "../vitest.plugins.config.ts";
import { createRuntimeConfigVitestConfig } from "../vitest.runtime-config.config.ts";
import { createScopedVitestConfig, resolveVitestIsolation } from "../vitest.scoped-config.ts";
import { createSecretsVitestConfig } from "../vitest.secrets.config.ts";
import { createSharedCoreVitestConfig } from "../vitest.shared-core.config.ts";
import { createToolingVitestConfig } from "../vitest.tooling.config.ts";
import { createUiVitestConfig } from "../vitest.ui.config.ts";
import { BUNDLED_PLUGIN_TEST_GLOB, bundledPluginFile } from "./helpers/bundled-plugin-paths.js";
@@ -76,24 +93,41 @@ describe("createScopedVitestConfig", () => {
describe("scoped vitest configs", () => {
const defaultChannelsConfig = createChannelsVitestConfig({});
const defaultAcpConfig = createAcpVitestConfig({});
const defaultCliConfig = createCliVitestConfig({});
const defaultExtensionsConfig = createExtensionsVitestConfig({});
const defaultExtensionAcpxConfig = createExtensionAcpxVitestConfig({});
const defaultExtensionBlueBubblesConfig = createExtensionBlueBubblesVitestConfig({});
const defaultExtensionChannelsConfig = createExtensionChannelsVitestConfig({});
const defaultExtensionDiffsConfig = createExtensionDiffsVitestConfig({});
const defaultExtensionMatrixConfig = createExtensionMatrixVitestConfig({});
const defaultExtensionMemoryConfig = createExtensionMemoryVitestConfig({});
const defaultExtensionMessagingConfig = createExtensionMessagingVitestConfig({});
const defaultExtensionProvidersConfig = createExtensionProvidersVitestConfig({});
const defaultExtensionTelegramConfig = createExtensionTelegramVitestConfig({});
const defaultGatewayConfig = createGatewayVitestConfig({});
const defaultInfraConfig = createInfraVitestConfig({});
const defaultPluginSdkConfig = createPluginSdkVitestConfig({});
const defaultSecretsConfig = createSecretsVitestConfig({});
const defaultRuntimeConfig = createRuntimeConfigVitestConfig({});
const defaultCronConfig = createCronVitestConfig({});
const defaultDaemonConfig = createDaemonVitestConfig({});
const defaultMediaConfig = createMediaVitestConfig({});
const defaultMediaUnderstandingConfig = createMediaUnderstandingVitestConfig({});
const defaultSharedCoreConfig = createSharedCoreVitestConfig({});
const defaultCommandsConfig = createCommandsVitestConfig({});
const defaultAutoReplyConfig = createAutoReplyVitestConfig({});
const defaultAgentsConfig = createAgentsVitestConfig({});
const defaultPluginsConfig = createPluginsVitestConfig({});
const defaultToolingConfig = createToolingVitestConfig({});
const defaultUiConfig = createUiVitestConfig({});
it("defaults channel tests to non-isolated mode", () => {
expect(defaultChannelsConfig.test?.isolate).toBe(false);
expect(defaultChannelsConfig.test?.pool).toBe("threads");
expect(defaultChannelsConfig.test?.pool).toBe("forks");
});
it("keeps the core channel lane limited to non-extension roots", () => {
expect(defaultChannelsConfig.test?.include).toEqual([]);
expect(defaultChannelsConfig.test?.include).toEqual(["src/channels/**/*.test.ts"]);
});
it("loads channel include overrides from OPENCLAW_VITEST_INCLUDE_FILE", () => {
@@ -125,7 +159,7 @@ describe("scoped vitest configs", () => {
it("defaults extension tests to non-isolated mode", () => {
expect(defaultExtensionsConfig.test?.isolate).toBe(false);
expect(defaultExtensionsConfig.test?.pool).toBe("threads");
expect(defaultExtensionsConfig.test?.pool).toBe("forks");
});
it("normalizes extension channel include patterns relative to the scoped dir", () => {
@@ -143,6 +177,21 @@ describe("scoped vitest configs", () => {
);
});
it("normalizes bluebubbles extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionBlueBubblesConfig.test?.dir).toBe("extensions");
expect(defaultExtensionBlueBubblesConfig.test?.include).toEqual(["bluebubbles/**/*.test.ts"]);
});
it("normalizes acpx extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionAcpxConfig.test?.dir).toBe("extensions");
expect(defaultExtensionAcpxConfig.test?.include).toEqual(["acpx/**/*.test.ts"]);
});
it("normalizes diffs extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionDiffsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionDiffsConfig.test?.include).toEqual(["diffs/**/*.test.ts"]);
});
it("normalizes extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionsConfig.test?.include).toEqual(["**/*.test.ts"]);
@@ -155,16 +204,40 @@ describe("scoped vitest configs", () => {
);
});
it("keeps telegram plugin tests in extensions while excluding channel-surface plugin roots", () => {
it("normalizes extension messaging include patterns relative to the scoped dir", () => {
expect(defaultExtensionMessagingConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMessagingConfig.test?.include).toEqual(
expect.arrayContaining(["feishu/**/*.test.ts"]),
);
});
it("normalizes matrix extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMatrixConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMatrixConfig.test?.include).toEqual(["matrix/**/*.test.ts"]);
});
it("normalizes telegram extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionTelegramConfig.test?.dir).toBe("extensions");
expect(defaultExtensionTelegramConfig.test?.include).toEqual(["telegram/**/*.test.ts"]);
});
it("normalizes memory extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMemoryConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMemoryConfig.test?.include).toEqual(
expect.arrayContaining(["memory-core/**/*.test.ts", "memory-lancedb/**/*.test.ts"]),
);
});
it("keeps telegram plugin tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) => path.matchesGlob("telegram/src/fetch.test.ts", pattern)),
).toBe(false);
).toBe(true);
expect(
extensionExcludes.some((pattern) =>
path.matchesGlob("telegram/src/bot/delivery.resolve-media-retry.test.ts", pattern),
),
).toBe(false);
).toBe(true);
expect(defaultChannelsConfig.test?.include).not.toContain("extensions/telegram/**/*.test.ts");
expect(defaultChannelsConfig.test?.exclude).not.toContain(
bundledPluginFile("telegram", "src/fetch.test.ts"),
@@ -174,6 +247,11 @@ describe("scoped vitest configs", () => {
"test/setup.extensions.ts",
"test/setup-openclaw-runtime.ts",
]);
expect(defaultExtensionTelegramConfig.test?.setupFiles).toEqual([
"test/setup.ts",
"test/setup.extensions.ts",
"test/setup-openclaw-runtime.ts",
]);
});
it("keeps provider plugin tests out of the shared extensions lane", () => {
@@ -185,6 +263,50 @@ describe("scoped vitest configs", () => {
).toBe(true);
});
it("keeps messaging plugin tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) => path.matchesGlob("matrix/src/channel.test.ts", pattern)),
).toBe(true);
});
it("normalizes secrets include patterns relative to the scoped dir", () => {
expect(defaultSecretsConfig.test?.dir).toBe("src/secrets");
expect(defaultSecretsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("keeps memory plugin tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) =>
path.matchesGlob("memory-core/src/memory/test-runtime-mocks.ts", pattern),
),
).toBe(true);
});
it("keeps bluebubbles tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) =>
path.matchesGlob("bluebubbles/src/monitor.test.ts", pattern),
),
).toBe(true);
});
it("keeps acpx tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) => path.matchesGlob("acpx/src/runtime.test.ts", pattern)),
).toBe(true);
});
it("keeps diffs tests out of the shared extensions lane", () => {
const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? [];
expect(
extensionExcludes.some((pattern) => path.matchesGlob("diffs/src/render.test.ts", pattern)),
).toBe(true);
});
it("normalizes gateway include patterns relative to the scoped dir", () => {
expect(defaultGatewayConfig.test?.dir).toBe("src/gateway");
expect(defaultGatewayConfig.test?.include).toEqual(["**/*.test.ts"]);
@@ -195,6 +317,43 @@ describe("scoped vitest configs", () => {
expect(defaultInfraConfig.test?.include).toEqual(["infra/**/*.test.ts"]);
});
it("normalizes runtime config include patterns relative to the scoped dir", () => {
expect(defaultRuntimeConfig.test?.dir).toBe("src");
expect(defaultRuntimeConfig.test?.include).toEqual(["config/**/*.test.ts"]);
});
it("normalizes cron include patterns relative to the scoped dir", () => {
expect(defaultCronConfig.test?.dir).toBe("src");
expect(defaultCronConfig.test?.include).toEqual(["cron/**/*.test.ts"]);
});
it("normalizes daemon include patterns relative to the scoped dir", () => {
expect(defaultDaemonConfig.test?.dir).toBe("src");
expect(defaultDaemonConfig.test?.include).toEqual(["daemon/**/*.test.ts"]);
});
it("normalizes media include patterns relative to the scoped dir", () => {
expect(defaultMediaConfig.test?.dir).toBe("src");
expect(defaultMediaConfig.test?.include).toEqual(["media/**/*.test.ts"]);
});
it("normalizes plugin-sdk include patterns relative to the scoped dir", () => {
expect(defaultPluginSdkConfig.test?.dir).toBe("src");
expect(defaultPluginSdkConfig.test?.include).toEqual(["plugin-sdk/**/*.test.ts"]);
});
it("normalizes shared-core include patterns relative to the scoped dir", () => {
expect(defaultSharedCoreConfig.test?.dir).toBe("src");
expect(defaultSharedCoreConfig.test?.include).toEqual(["shared/**/*.test.ts"]);
});
it("normalizes media-understanding include patterns relative to the scoped dir", () => {
expect(defaultMediaUnderstandingConfig.test?.dir).toBe("src");
expect(defaultMediaUnderstandingConfig.test?.include).toEqual([
"media-understanding/**/*.test.ts",
]);
});
it("keeps tooling tests in their own lane", () => {
expect(defaultToolingConfig.test?.include).toEqual(
expect.arrayContaining([
@@ -210,6 +369,11 @@ describe("scoped vitest configs", () => {
expect(defaultAcpConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes cli include patterns relative to the scoped dir", () => {
expect(defaultCliConfig.test?.dir).toBe("src/cli");
expect(defaultCliConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes commands include patterns relative to the scoped dir", () => {
expect(defaultCommandsConfig.test?.dir).toBe("src/commands");
expect(defaultCommandsConfig.test?.include).toEqual(["**/*.test.ts"]);
@@ -225,6 +389,11 @@ describe("scoped vitest configs", () => {
expect(defaultAgentsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes plugins include patterns relative to the scoped dir", () => {
expect(defaultPluginsConfig.test?.dir).toBe("src/plugins");
expect(defaultPluginsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes ui include patterns relative to the scoped dir", () => {
expect(defaultUiConfig.test?.dir).toBe("ui/src/ui");
expect(defaultUiConfig.test?.include).toEqual(["**/*.test.ts"]);

View File

@@ -11,6 +11,7 @@ export const extensionRoutedChannelTestFiles = [];
const extensionRoutedChannelTestFileSet = new Set(extensionRoutedChannelTestFiles);
export const channelTestRoots = [
"src/channels",
bundledPluginRoot("discord"),
bundledPluginRoot("whatsapp"),
bundledPluginRoot("slack"),

View File

@@ -11,7 +11,7 @@ export function loadIncludePatternsFromEnv(
export function createChannelsVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(loadIncludePatternsFromEnv(env) ?? coreChannelTestInclude, {
env,
exclude: ["src/gateway/**"],
exclude: ["src/gateway/**", "src/channels/plugins/contracts/**"],
name: "channels",
passWithNoTests: true,
});

12
vitest.cli.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createCliVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/cli/**/*.test.ts"], {
dir: "src/cli",
env,
name: "cli",
passWithNoTests: true,
});
}
export default createCliVitestConfig();

View File

@@ -15,14 +15,31 @@ export const rootVitestProjects = [
"vitest.bundled.config.ts",
"vitest.gateway.config.ts",
"vitest.acp.config.ts",
"vitest.runtime-config.config.ts",
"vitest.secrets.config.ts",
"vitest.cli.config.ts",
"vitest.commands.config.ts",
"vitest.auto-reply.config.ts",
"vitest.agents.config.ts",
"vitest.daemon.config.ts",
"vitest.media.config.ts",
"vitest.plugin-sdk.config.ts",
"vitest.plugins.config.ts",
"vitest.cron.config.ts",
"vitest.media-understanding.config.ts",
"vitest.shared-core.config.ts",
"vitest.tooling.config.ts",
"vitest.ui.config.ts",
"vitest.channels.config.ts",
"vitest.extension-acpx.config.ts",
"vitest.extension-bluebubbles.config.ts",
"vitest.extension-channels.config.ts",
"vitest.extension-diffs.config.ts",
"vitest.extension-matrix.config.ts",
"vitest.extension-memory.config.ts",
"vitest.extension-messaging.config.ts",
"vitest.extension-providers.config.ts",
"vitest.extension-telegram.config.ts",
"vitest.extensions.config.ts",
] as const;

12
vitest.cron.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createCronVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/cron/**/*.test.ts"], {
dir: "src",
env,
name: "cron",
passWithNoTests: true,
});
}
export default createCronVitestConfig();

12
vitest.daemon.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createDaemonVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/daemon/**/*.test.ts"], {
dir: "src",
env,
name: "daemon",
passWithNoTests: true,
});
}
export default createDaemonVitestConfig();

View File

@@ -0,0 +1,5 @@
export const acpxExtensionTestRoots = ["extensions/acpx"];
export function isAcpxExtensionRoot(root) {
return acpxExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,26 @@
import { acpxExtensionTestRoots } from "./vitest.extension-acpx-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionAcpxVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ?? acpxExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-acpx",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionAcpxVitestConfig();

View File

@@ -0,0 +1,5 @@
export const blueBubblesExtensionTestRoots = ["extensions/bluebubbles"];
export function isBlueBubblesExtensionRoot(root) {
return blueBubblesExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,27 @@
import { blueBubblesExtensionTestRoots } from "./vitest.extension-bluebubbles-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionBlueBubblesVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ??
blueBubblesExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-bluebubbles",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionBlueBubblesVitestConfig();

View File

@@ -0,0 +1,5 @@
export const diffsExtensionTestRoots = ["extensions/diffs"];
export function isDiffsExtensionRoot(root) {
return diffsExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,27 @@
import { diffsExtensionTestRoots } from "./vitest.extension-diffs-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionDiffsVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ??
diffsExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-diffs",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionDiffsVitestConfig();

View File

@@ -0,0 +1,9 @@
import { bundledPluginRoot } from "./scripts/lib/bundled-plugin-paths.mjs";
export const matrixExtensionIds = ["matrix"];
export const matrixExtensionTestRoots = matrixExtensionIds.map((id) => bundledPluginRoot(id));
export function isMatrixExtensionRoot(root) {
return matrixExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,17 @@
import { matrixExtensionTestRoots } from "./vitest.extension-matrix-paths.mjs";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createExtensionMatrixVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(
matrixExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-matrix",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionMatrixVitestConfig();

View File

@@ -0,0 +1,5 @@
export const memoryExtensionTestRoots = ["extensions/memory-core", "extensions/memory-lancedb"];
export function isMemoryExtensionRoot(root) {
return memoryExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,27 @@
import { memoryExtensionTestRoots } from "./vitest.extension-memory-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionMemoryVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ??
memoryExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-memory",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionMemoryVitestConfig();

View File

@@ -0,0 +1,25 @@
import { bundledPluginRoot } from "./scripts/lib/bundled-plugin-paths.mjs";
export const messagingExtensionIds = [
"bluebubbles",
"feishu",
"googlechat",
"irc",
"mattermost",
"msteams",
"nextcloud-talk",
"nostr",
"qqbot",
"synology-chat",
"tlon",
"twitch",
"voice-call",
"zalo",
"zalouser",
];
export const messagingExtensionTestRoots = messagingExtensionIds.map((id) => bundledPluginRoot(id));
export function isMessagingExtensionRoot(root) {
return messagingExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,27 @@
import { messagingExtensionTestRoots } from "./vitest.extension-messaging-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionMessagingVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ??
messagingExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-messaging",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionMessagingVitestConfig();

View File

@@ -0,0 +1,5 @@
export const telegramExtensionTestRoots = ["extensions/telegram"];
export function isTelegramExtensionRoot(root) {
return telegramExtensionTestRoots.includes(root);
}

View File

@@ -0,0 +1,27 @@
import { telegramExtensionTestRoots } from "./vitest.extension-telegram-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function loadIncludePatternsFromEnv(
env: Record<string, string | undefined> = process.env,
): string[] | null {
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
}
export function createExtensionTelegramVitestConfig(
env: Record<string, string | undefined> = process.env,
) {
return createScopedVitestConfig(
loadIncludePatternsFromEnv(env) ??
telegramExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
{
dir: "extensions",
env,
name: "extension-telegram",
passWithNoTests: true,
setupFiles: ["test/setup.extensions.ts"],
},
);
}
export default createExtensionTelegramVitestConfig();

View File

@@ -1,6 +1,13 @@
import { BUNDLED_PLUGIN_TEST_GLOB } from "./vitest.bundled-plugin-paths.ts";
import { extensionExcludedChannelTestGlobs } from "./vitest.channel-paths.mjs";
import { acpxExtensionTestRoots } from "./vitest.extension-acpx-paths.mjs";
import { blueBubblesExtensionTestRoots } from "./vitest.extension-bluebubbles-paths.mjs";
import { diffsExtensionTestRoots } from "./vitest.extension-diffs-paths.mjs";
import { matrixExtensionTestRoots } from "./vitest.extension-matrix-paths.mjs";
import { memoryExtensionTestRoots } from "./vitest.extension-memory-paths.mjs";
import { messagingExtensionTestRoots } from "./vitest.extension-messaging-paths.mjs";
import { providerExtensionTestRoots } from "./vitest.extension-provider-paths.mjs";
import { telegramExtensionTestRoots } from "./vitest.extension-telegram-paths.mjs";
import { loadPatternListFromEnv } from "./vitest.pattern-file.ts";
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
@@ -23,7 +30,14 @@ export function createExtensionsVitestConfig(
// out of the shared extensions lane.
exclude: [
...extensionExcludedChannelTestGlobs,
...acpxExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...blueBubblesExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...diffsExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...matrixExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...memoryExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...messagingExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...providerExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
...telegramExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
],
});
}

View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createMediaUnderstandingVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/media-understanding/**/*.test.ts"], {
dir: "src",
env,
name: "media-understanding",
passWithNoTests: true,
});
}
export default createMediaUnderstandingVitestConfig();

12
vitest.media.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createMediaVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/media/**/*.test.ts"], {
dir: "src",
env,
name: "media",
passWithNoTests: true,
});
}
export default createMediaVitestConfig();

View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createPluginSdkVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/plugin-sdk/**/*.test.ts"], {
dir: "src",
env,
name: "plugin-sdk",
passWithNoTests: true,
});
}
export default createPluginSdkVitestConfig();

12
vitest.plugins.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createPluginsVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/plugins/**/*.test.ts"], {
dir: "src/plugins",
env,
name: "plugins",
passWithNoTests: true,
});
}
export default createPluginsVitestConfig();

View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createRuntimeConfigVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/config/**/*.test.ts"], {
dir: "src",
env,
name: "runtime-config",
passWithNoTests: true,
});
}
export default createRuntimeConfigVitestConfig();

View File

@@ -48,7 +48,7 @@ export function createScopedVitestConfig(
includeOpenClawRuntimeSetup?: boolean;
isolate?: boolean;
name?: string;
pool?: "threads" | "forks";
pool?: "forks";
passWithNoTests?: boolean;
setupFiles?: string[];
useNonIsolatedRunner?: boolean;

12
vitest.secrets.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createSecretsVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/secrets/**/*.test.ts"], {
dir: "src/secrets",
env,
name: "secrets",
passWithNoTests: true,
});
}
export default createSecretsVitestConfig();

View File

@@ -0,0 +1,12 @@
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createSharedCoreVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(["src/shared/**/*.test.ts"], {
dir: "src",
env,
name: "shared-core",
passWithNoTests: true,
});
}
export default createSharedCoreVitestConfig();

View File

@@ -21,7 +21,7 @@ type VitestHostInfo = {
totalMemoryBytes?: number;
};
export type OpenClawVitestPool = "threads" | "forks";
export type OpenClawVitestPool = "forks";
export const jsdomOptimizedDeps = {
optimizer: {
@@ -97,10 +97,10 @@ export function resolveDefaultVitestPool(
env: Record<string, string | undefined> = process.env,
): OpenClawVitestPool {
const configuredPool = (env.OPENCLAW_VITEST_POOL ?? env.OPENCLAW_TEST_POOL)?.trim();
if (configuredPool === "threads" || configuredPool === "forks") {
return configuredPool;
if (configuredPool && configuredPool !== "forks") {
return "forks";
}
return "threads";
return "forks";
}
const repoRoot = path.dirname(fileURLToPath(import.meta.url));
@@ -146,21 +146,45 @@ export const sharedVitestConfig = {
"vitest.acp.config.ts",
"vitest.boundary.config.ts",
"vitest.bundled.config.ts",
"vitest.cli.config.ts",
"vitest.config.ts",
"vitest.contracts.config.ts",
"vitest.cron.config.ts",
"vitest.daemon.config.ts",
"vitest.e2e.config.ts",
"vitest.extension-acpx-paths.mjs",
"vitest.extension-acpx.config.ts",
"vitest.extension-bluebubbles-paths.mjs",
"vitest.extension-bluebubbles.config.ts",
"vitest.extension-channels.config.ts",
"vitest.extension-diffs-paths.mjs",
"vitest.extension-diffs.config.ts",
"vitest.extension-matrix-paths.mjs",
"vitest.extension-matrix.config.ts",
"vitest.extension-memory-paths.mjs",
"vitest.extension-memory.config.ts",
"vitest.extension-messaging-paths.mjs",
"vitest.extension-messaging.config.ts",
"vitest.extensions.config.ts",
"vitest.gateway.config.ts",
"vitest.infra.config.ts",
"vitest.live.config.ts",
"vitest.media.config.ts",
"vitest.media-understanding.config.ts",
"vitest.performance-config.ts",
"vitest.scoped-config.ts",
"vitest.shared-core.config.ts",
"vitest.shared.config.ts",
"vitest.tooling.config.ts",
"vitest.ui.config.ts",
"vitest.unit.config.ts",
"vitest.unit-paths.mjs",
"vitest.runtime-config.config.ts",
"vitest.secrets.config.ts",
"vitest.plugin-sdk.config.ts",
"vitest.plugins.config.ts",
"vitest.extension-telegram-paths.mjs",
"vitest.extension-telegram.config.ts",
"vitest.extension-provider-paths.mjs",
"vitest.extension-providers.config.ts",
],
@@ -235,6 +259,7 @@ export const sharedVitestConfig = {
"src/node-host/**",
"src/plugins/**",
"src/providers/**",
"src/secrets/**",
"src/agents/model-scan.ts",
"src/agents/pi-embedded-runner.ts",
"src/agents/sandbox-paths.ts",

View File

@@ -46,8 +46,18 @@ export const unitTestAdditionalExcludePatterns = [
"src/line/**",
"src/agents/**",
"src/auto-reply/**",
"src/channels/**",
"src/cli/**",
"src/commands/**",
"src/channels/plugins/contracts/**",
"src/config/**",
"src/cron/**",
"src/daemon/**",
"src/media/**",
"src/plugin-sdk/**",
"src/plugins/**",
"src/secrets/**",
"src/shared/**",
"src/media-understanding/**",
"src/plugins/contracts/**",
"src/scripts/**",
"src/infra/boundary-path.test.ts",