mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-12 22:30:51 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
11
openclaw/test/vitest/vitest.acp.config.ts
Normal file
11
openclaw/test/vitest/vitest.acp.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createAcpVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/acp/**/*.test.ts"], {
|
||||
dir: "src/acp",
|
||||
env,
|
||||
name: "acp",
|
||||
});
|
||||
}
|
||||
|
||||
export default createAcpVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.agents.config.ts
Normal file
12
openclaw/test/vitest/vitest.agents.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createAgentsVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/agents/**/*.test.ts"], {
|
||||
dir: "src/agents",
|
||||
env,
|
||||
fileParallelism: false,
|
||||
name: "agents",
|
||||
});
|
||||
}
|
||||
|
||||
export default createAgentsVitestConfig();
|
||||
13
openclaw/test/vitest/vitest.auto-reply-core.config.ts
Normal file
13
openclaw/test/vitest/vitest.auto-reply-core.config.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { autoReplyCoreTestExclude, autoReplyCoreTestInclude } from "./vitest.test-shards.mjs";
|
||||
|
||||
export function createAutoReplyCoreVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig([...autoReplyCoreTestInclude], {
|
||||
dir: "src/auto-reply",
|
||||
env,
|
||||
exclude: [...autoReplyCoreTestExclude],
|
||||
name: "auto-reply-core",
|
||||
});
|
||||
}
|
||||
|
||||
export default createAutoReplyCoreVitestConfig();
|
||||
17
openclaw/test/vitest/vitest.auto-reply-reply.config.ts
Normal file
17
openclaw/test/vitest/vitest.auto-reply-reply.config.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { autoReplyReplySubtreeTestInclude } from "./vitest.test-shards.mjs";
|
||||
|
||||
export function createAutoReplyReplyVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig([...autoReplyReplySubtreeTestInclude], {
|
||||
dir: "src/auto-reply",
|
||||
env,
|
||||
fileParallelism: false,
|
||||
maxWorkers: 1,
|
||||
name: "auto-reply-reply",
|
||||
sequence: {
|
||||
groupOrder: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default createAutoReplyReplyVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.auto-reply-top-level.config.ts
Normal file
12
openclaw/test/vitest/vitest.auto-reply-top-level.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { autoReplyTopLevelReplyTestInclude } from "./vitest.test-shards.mjs";
|
||||
|
||||
export function createAutoReplyTopLevelVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig([...autoReplyTopLevelReplyTestInclude], {
|
||||
dir: "src/auto-reply",
|
||||
env,
|
||||
name: "auto-reply-top-level",
|
||||
});
|
||||
}
|
||||
|
||||
export default createAutoReplyTopLevelVitestConfig();
|
||||
11
openclaw/test/vitest/vitest.auto-reply.config.ts
Normal file
11
openclaw/test/vitest/vitest.auto-reply.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createAutoReplyVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/auto-reply/**/*.test.ts"], {
|
||||
dir: "src/auto-reply",
|
||||
env,
|
||||
name: "auto-reply",
|
||||
});
|
||||
}
|
||||
|
||||
export default createAutoReplyVitestConfig();
|
||||
35
openclaw/test/vitest/vitest.boundary.config.ts
Normal file
35
openclaw/test/vitest/vitest.boundary.config.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { defineProject } from "vitest/config";
|
||||
import { loadPatternListFromEnv, narrowIncludePatternsForCli } from "./vitest.pattern-file.ts";
|
||||
import { resolveVitestIsolation } from "./vitest.scoped-config.ts";
|
||||
import { nonIsolatedRunnerPath, sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
import { boundaryTestFiles } from "./vitest.unit-paths.mjs";
|
||||
|
||||
export function loadBoundaryIncludePatternsFromEnv(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): string[] | null {
|
||||
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
|
||||
}
|
||||
|
||||
export function createBoundaryVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
argv: string[] = process.argv,
|
||||
) {
|
||||
const cliIncludePatterns = narrowIncludePatternsForCli(boundaryTestFiles, argv);
|
||||
const isolate = resolveVitestIsolation(env);
|
||||
return defineProject({
|
||||
...sharedVitestConfig,
|
||||
test: {
|
||||
...sharedVitestConfig.test,
|
||||
name: "boundary",
|
||||
isolate,
|
||||
...(isolate ? { runner: undefined } : { runner: nonIsolatedRunnerPath }),
|
||||
include: loadBoundaryIncludePatternsFromEnv(env) ?? cliIncludePatterns ?? boundaryTestFiles,
|
||||
...(cliIncludePatterns !== null ? { passWithNoTests: true } : {}),
|
||||
// Boundary workers still need the shared isolated HOME/bootstrap. Only
|
||||
// per-file module isolation is disabled here.
|
||||
setupFiles: sharedVitestConfig.test.setupFiles,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default createBoundaryVitestConfig();
|
||||
5
openclaw/test/vitest/vitest.bundled-plugin-paths.ts
Normal file
5
openclaw/test/vitest/vitest.bundled-plugin-paths.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const BUNDLED_PLUGIN_ROOT_DIR = "extensions";
|
||||
export const BUNDLED_PLUGIN_PATH_PREFIX = `${BUNDLED_PLUGIN_ROOT_DIR}/`;
|
||||
export const BUNDLED_PLUGIN_TEST_GLOB = `${BUNDLED_PLUGIN_ROOT_DIR}/**/*.test.ts`;
|
||||
export const BUNDLED_PLUGIN_E2E_TEST_GLOB = `${BUNDLED_PLUGIN_ROOT_DIR}/**/*.e2e.test.ts`;
|
||||
export const BUNDLED_PLUGIN_LIVE_TEST_GLOB = `${BUNDLED_PLUGIN_ROOT_DIR}/**/*.live.test.ts`;
|
||||
36
openclaw/test/vitest/vitest.bundled.config.ts
Normal file
36
openclaw/test/vitest/vitest.bundled.config.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import path from "node:path";
|
||||
import {
|
||||
bundledPluginDependentUnitTestFiles,
|
||||
unitTestAdditionalExcludePatterns,
|
||||
} from "./vitest.unit-paths.mjs";
|
||||
import { createUnitVitestConfigWithOptions } from "./vitest.unit.config.ts";
|
||||
|
||||
function normalizeGlobCandidate(value: string): string {
|
||||
return value.split(path.sep).join("/");
|
||||
}
|
||||
|
||||
function excludePatternCouldMatchFile(pattern: string, file: string): boolean {
|
||||
const normalizedPattern = normalizeGlobCandidate(pattern);
|
||||
const normalizedFile = normalizeGlobCandidate(file);
|
||||
if (normalizedPattern === normalizedFile) {
|
||||
return true;
|
||||
}
|
||||
if (normalizedPattern.endsWith("/**")) {
|
||||
const prefix = normalizedPattern.slice(0, -3);
|
||||
return normalizedFile === prefix || normalizedFile.startsWith(`${prefix}/`);
|
||||
}
|
||||
return path.matchesGlob(normalizedFile, normalizedPattern);
|
||||
}
|
||||
|
||||
const bundledUnitExcludePatterns = unitTestAdditionalExcludePatterns.filter(
|
||||
(pattern) =>
|
||||
!bundledPluginDependentUnitTestFiles.some((file) =>
|
||||
excludePatternCouldMatchFile(pattern, file),
|
||||
),
|
||||
);
|
||||
|
||||
export default createUnitVitestConfigWithOptions(process.env, {
|
||||
includePatterns: bundledPluginDependentUnitTestFiles,
|
||||
extraExcludePatterns: bundledUnitExcludePatterns,
|
||||
name: "bundled",
|
||||
});
|
||||
75
openclaw/test/vitest/vitest.channel-paths.mjs
Normal file
75
openclaw/test/vitest/vitest.channel-paths.mjs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import path from "node:path";
|
||||
import {
|
||||
BUNDLED_PLUGIN_PATH_PREFIX,
|
||||
bundledPluginRoot,
|
||||
} from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
const normalizeRepoPath = (value) => value.split(path.sep).join("/");
|
||||
|
||||
export const extensionRoutedChannelTestFiles = [];
|
||||
|
||||
const extensionRoutedChannelTestFileSet = new Set(extensionRoutedChannelTestFiles);
|
||||
|
||||
export const channelTestRoots = [
|
||||
"src/channels",
|
||||
bundledPluginRoot("discord"),
|
||||
bundledPluginRoot("slack"),
|
||||
bundledPluginRoot("signal"),
|
||||
bundledPluginRoot("imessage"),
|
||||
bundledPluginRoot("line"),
|
||||
];
|
||||
|
||||
export const extensionChannelTestRoots = channelTestRoots.filter((root) =>
|
||||
root.startsWith(BUNDLED_PLUGIN_PATH_PREFIX),
|
||||
);
|
||||
export const coreChannelTestRoots = channelTestRoots.filter(
|
||||
(root) => !root.startsWith(BUNDLED_PLUGIN_PATH_PREFIX),
|
||||
);
|
||||
export const channelTestPrefixes = channelTestRoots.map((root) => `${root}/`);
|
||||
export const channelTestInclude = channelTestRoots.map((root) => `${root}/**/*.test.ts`);
|
||||
export const extensionChannelTestInclude = extensionChannelTestRoots.map(
|
||||
(root) => `${root}/**/*.test.ts`,
|
||||
);
|
||||
export const coreChannelTestInclude = coreChannelTestRoots.map((root) => `${root}/**/*.test.ts`);
|
||||
export const channelTestExclude = channelTestRoots.map((root) => `${root}/**`);
|
||||
|
||||
const extensionChannelRootOverrideBasenames = new Map();
|
||||
for (const file of extensionRoutedChannelTestFiles) {
|
||||
if (!file.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
const relativeFile = file.slice(BUNDLED_PLUGIN_PATH_PREFIX.length);
|
||||
const separator = relativeFile.indexOf("/");
|
||||
if (separator === -1) {
|
||||
continue;
|
||||
}
|
||||
const root = relativeFile.slice(0, separator);
|
||||
const baseName = path.basename(relativeFile, ".test.ts");
|
||||
const current = extensionChannelRootOverrideBasenames.get(root) ?? [];
|
||||
current.push(baseName);
|
||||
extensionChannelRootOverrideBasenames.set(root, current);
|
||||
}
|
||||
|
||||
export const extensionExcludedChannelTestGlobs = channelTestRoots
|
||||
.filter((root) => root.startsWith(BUNDLED_PLUGIN_PATH_PREFIX))
|
||||
.map((root) => root.slice(BUNDLED_PLUGIN_PATH_PREFIX.length))
|
||||
.map((relativeRoot) => {
|
||||
const allowedBasenames = extensionChannelRootOverrideBasenames.get(relativeRoot) ?? [];
|
||||
if (allowedBasenames.length === 0) {
|
||||
return `${relativeRoot}/**`;
|
||||
}
|
||||
const alternation = allowedBasenames.join("|");
|
||||
return `${relativeRoot}/**/!(${alternation}).test.ts`;
|
||||
});
|
||||
|
||||
export const extensionChannelOverrideExcludeGlobs = extensionRoutedChannelTestFiles
|
||||
.filter((file) => file.startsWith(BUNDLED_PLUGIN_PATH_PREFIX))
|
||||
.map((file) => file.slice(BUNDLED_PLUGIN_PATH_PREFIX.length));
|
||||
|
||||
export function isChannelSurfaceTestFile(filePath) {
|
||||
const normalizedFile = normalizeRepoPath(filePath);
|
||||
return (
|
||||
channelTestPrefixes.some((prefix) => normalizedFile.startsWith(prefix)) &&
|
||||
!extensionRoutedChannelTestFileSet.has(normalizedFile)
|
||||
);
|
||||
}
|
||||
20
openclaw/test/vitest/vitest.channels.config.ts
Normal file
20
openclaw/test/vitest/vitest.channels.config.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { coreChannelTestInclude } from "./vitest.channel-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 createChannelsVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(loadIncludePatternsFromEnv(env) ?? coreChannelTestInclude, {
|
||||
env,
|
||||
exclude: ["src/gateway/**", "src/channels/plugins/contracts/**"],
|
||||
name: "channels",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createChannelsVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.cli.config.ts
Normal file
12
openclaw/test/vitest/vitest.cli.config.ts
Normal 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();
|
||||
69
openclaw/test/vitest/vitest.commands-light-paths.mjs
Normal file
69
openclaw/test/vitest/vitest.commands-light-paths.mjs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
const normalizeRepoPath = (value) => value.replaceAll("\\", "/");
|
||||
|
||||
const commandsLightEntries = [
|
||||
{ source: "src/commands/cleanup-utils.ts", test: "src/commands/cleanup-utils.test.ts" },
|
||||
{
|
||||
source: "src/commands/dashboard.links.ts",
|
||||
test: "src/commands/dashboard.links.test.ts",
|
||||
},
|
||||
{ source: "src/commands/doctor-browser.ts", test: "src/commands/doctor-browser.test.ts" },
|
||||
{
|
||||
source: "src/commands/doctor-gateway-auth-token.ts",
|
||||
test: "src/commands/doctor-gateway-auth-token.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/gateway-status/helpers.ts",
|
||||
test: "src/commands/gateway-status/helpers.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/sandbox-formatters.ts",
|
||||
test: "src/commands/sandbox-formatters.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-json-command.ts",
|
||||
test: "src/commands/status-json-command.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-json-payload.ts",
|
||||
test: "src/commands/status-json-payload.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-json-runtime.ts",
|
||||
test: "src/commands/status-json-runtime.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-overview-rows.ts",
|
||||
test: "src/commands/status-overview-rows.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-overview-surface.ts",
|
||||
test: "src/commands/status-overview-surface.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/commands/status-overview-values.ts",
|
||||
test: "src/commands/status-overview-values.test.ts",
|
||||
},
|
||||
{ source: "src/commands/text-format.ts", test: "src/commands/text-format.test.ts" },
|
||||
];
|
||||
|
||||
const commandsLightIncludePatternByFile = new Map(
|
||||
commandsLightEntries.flatMap(({ source, test }) => [
|
||||
[source, test],
|
||||
[test, test],
|
||||
]),
|
||||
);
|
||||
|
||||
export const commandsLightSourceFiles = commandsLightEntries.map(({ source }) => source);
|
||||
export const commandsLightTestFiles = commandsLightEntries.map(({ test }) => test);
|
||||
|
||||
export function isCommandsLightTarget(file) {
|
||||
return commandsLightIncludePatternByFile.has(normalizeRepoPath(file));
|
||||
}
|
||||
|
||||
export function isCommandsLightTestFile(file) {
|
||||
return commandsLightTestFiles.includes(normalizeRepoPath(file));
|
||||
}
|
||||
|
||||
export function resolveCommandsLightIncludePattern(file) {
|
||||
return commandsLightIncludePatternByFile.get(normalizeRepoPath(file)) ?? null;
|
||||
}
|
||||
16
openclaw/test/vitest/vitest.commands-light.config.ts
Normal file
16
openclaw/test/vitest/vitest.commands-light.config.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { commandsLightTestFiles } from "./vitest.commands-light-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { getUnitFastTestFiles } from "./vitest.unit-fast-paths.mjs";
|
||||
|
||||
export function createCommandsLightVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(commandsLightTestFiles, {
|
||||
dir: "src/commands",
|
||||
env,
|
||||
exclude: getUnitFastTestFiles(),
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
name: "commands-light",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createCommandsLightVitestConfig();
|
||||
13
openclaw/test/vitest/vitest.commands.config.ts
Normal file
13
openclaw/test/vitest/vitest.commands.config.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { commandsLightTestFiles } from "./vitest.commands-light-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createCommandsVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/commands/**/*.test.ts"], {
|
||||
dir: "src/commands",
|
||||
env,
|
||||
exclude: commandsLightTestFiles,
|
||||
name: "commands",
|
||||
});
|
||||
}
|
||||
|
||||
export default createCommandsVitestConfig();
|
||||
75
openclaw/test/vitest/vitest.config.ts
Normal file
75
openclaw/test/vitest/vitest.config.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import {
|
||||
resolveDefaultVitestPool,
|
||||
resolveLocalVitestMaxWorkers,
|
||||
resolveLocalVitestScheduling,
|
||||
nonIsolatedRunnerPath,
|
||||
sharedVitestConfig,
|
||||
} from "./vitest.shared.config.ts";
|
||||
|
||||
export { resolveDefaultVitestPool, resolveLocalVitestMaxWorkers, resolveLocalVitestScheduling };
|
||||
|
||||
export const rootVitestProjects = [
|
||||
"test/vitest/vitest.unit.config.ts",
|
||||
"test/vitest/vitest.infra.config.ts",
|
||||
"test/vitest/vitest.boundary.config.ts",
|
||||
"test/vitest/vitest.contracts.config.ts",
|
||||
"test/vitest/vitest.bundled.config.ts",
|
||||
"test/vitest/vitest.gateway-core.config.ts",
|
||||
"test/vitest/vitest.gateway-client.config.ts",
|
||||
"test/vitest/vitest.gateway-methods.config.ts",
|
||||
"test/vitest/vitest.gateway-server.config.ts",
|
||||
"test/vitest/vitest.hooks.config.ts",
|
||||
"test/vitest/vitest.acp.config.ts",
|
||||
"test/vitest/vitest.runtime-config.config.ts",
|
||||
"test/vitest/vitest.secrets.config.ts",
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
"test/vitest/vitest.commands.config.ts",
|
||||
"test/vitest/vitest.auto-reply.config.ts",
|
||||
"test/vitest/vitest.agents.config.ts",
|
||||
"test/vitest/vitest.daemon.config.ts",
|
||||
"test/vitest/vitest.media.config.ts",
|
||||
"test/vitest/vitest.unit-fast.config.ts",
|
||||
"test/vitest/vitest.plugin-sdk-light.config.ts",
|
||||
"test/vitest/vitest.plugin-sdk.config.ts",
|
||||
"test/vitest/vitest.plugins.config.ts",
|
||||
"test/vitest/vitest.logging.config.ts",
|
||||
"test/vitest/vitest.process.config.ts",
|
||||
"test/vitest/vitest.cron.config.ts",
|
||||
"test/vitest/vitest.media-understanding.config.ts",
|
||||
"test/vitest/vitest.shared-core.config.ts",
|
||||
"test/vitest/vitest.tasks.config.ts",
|
||||
"test/vitest/vitest.tooling.config.ts",
|
||||
"test/vitest/vitest.tui.config.ts",
|
||||
"test/vitest/vitest.ui.config.ts",
|
||||
"test/vitest/vitest.utils.config.ts",
|
||||
"test/vitest/vitest.wizard.config.ts",
|
||||
"test/vitest/vitest.channels.config.ts",
|
||||
"test/vitest/vitest.extension-acpx.config.ts",
|
||||
"test/vitest/vitest.extension-bluebubbles.config.ts",
|
||||
"test/vitest/vitest.extension-channels.config.ts",
|
||||
"test/vitest/vitest.extension-diffs.config.ts",
|
||||
"test/vitest/vitest.extension-feishu.config.ts",
|
||||
"test/vitest/vitest.extension-irc.config.ts",
|
||||
"test/vitest/vitest.extension-mattermost.config.ts",
|
||||
"test/vitest/vitest.extension-matrix.config.ts",
|
||||
"test/vitest/vitest.extension-memory.config.ts",
|
||||
"test/vitest/vitest.extension-msteams.config.ts",
|
||||
"test/vitest/vitest.extension-messaging.config.ts",
|
||||
"test/vitest/vitest.extension-providers.config.ts",
|
||||
"test/vitest/vitest.extension-telegram.config.ts",
|
||||
"test/vitest/vitest.extension-voice-call.config.ts",
|
||||
"test/vitest/vitest.extension-whatsapp.config.ts",
|
||||
"test/vitest/vitest.extension-zalo.config.ts",
|
||||
"test/vitest/vitest.extensions.config.ts",
|
||||
] as const;
|
||||
|
||||
export default defineConfig({
|
||||
...sharedVitestConfig,
|
||||
test: {
|
||||
...sharedVitestConfig.test,
|
||||
runner: nonIsolatedRunnerPath,
|
||||
projects: [...rootVitestProjects],
|
||||
},
|
||||
});
|
||||
41
openclaw/test/vitest/vitest.contracts.config.ts
Normal file
41
openclaw/test/vitest/vitest.contracts.config.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { loadPatternListFromEnv, narrowIncludePatternsForCli } from "./vitest.pattern-file.ts";
|
||||
import { nonIsolatedRunnerPath, sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
|
||||
const base = sharedVitestConfig as Record<string, unknown>;
|
||||
const baseTest = sharedVitestConfig.test ?? {};
|
||||
const contractIncludePatterns = [
|
||||
"src/channels/plugins/contracts/**/*.test.ts",
|
||||
"src/plugins/contracts/**/*.test.ts",
|
||||
];
|
||||
|
||||
export function loadContractsIncludePatternsFromEnv(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): string[] | null {
|
||||
return loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
|
||||
}
|
||||
|
||||
export function createContractsVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
argv: string[] = process.argv,
|
||||
) {
|
||||
const cliIncludePatterns = narrowIncludePatternsForCli(contractIncludePatterns, argv);
|
||||
return defineConfig({
|
||||
...base,
|
||||
test: {
|
||||
...baseTest,
|
||||
isolate: false,
|
||||
// The contracts shard intentionally runs non-isolated and loads hundreds of
|
||||
// contract files. Use forks so full-suite parallel runs do not hit
|
||||
// Vitest worker-thread heap limits.
|
||||
pool: "forks",
|
||||
runner: nonIsolatedRunnerPath,
|
||||
setupFiles: baseTest.setupFiles ?? [],
|
||||
include:
|
||||
loadContractsIncludePatternsFromEnv(env) ?? cliIncludePatterns ?? contractIncludePatterns,
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default createContractsVitestConfig();
|
||||
22
openclaw/test/vitest/vitest.cron.config.ts
Normal file
22
openclaw/test/vitest/vitest.cron.config.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createCronVitestConfig(env?: Record<string, string | undefined>) {
|
||||
const config = createScopedVitestConfig(["src/cron/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
name: "cron",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
config.test = {
|
||||
...config.test,
|
||||
maxWorkers: 1,
|
||||
fileParallelism: false,
|
||||
sequence: {
|
||||
...config.test?.sequence,
|
||||
groupOrder: 1,
|
||||
},
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
export default createCronVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.daemon.config.ts
Normal file
12
openclaw/test/vitest/vitest.daemon.config.ts
Normal 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();
|
||||
50
openclaw/test/vitest/vitest.e2e.config.ts
Normal file
50
openclaw/test/vitest/vitest.e2e.config.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import os from "node:os";
|
||||
import { defineConfig } from "vitest/config";
|
||||
import { BUNDLED_PLUGIN_E2E_TEST_GLOB } from "./vitest.bundled-plugin-paths.ts";
|
||||
import baseConfig from "./vitest.config.ts";
|
||||
import { resolveRepoRootPath } from "./vitest.shared.config.ts";
|
||||
|
||||
const base = baseConfig as unknown as Record<string, unknown>;
|
||||
const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
||||
const cpuCount = os.cpus().length;
|
||||
// Keep e2e runs cheap by default; callers can still override via OPENCLAW_E2E_WORKERS.
|
||||
const defaultWorkers = isCI ? Math.min(2, Math.max(1, Math.floor(cpuCount * 0.25))) : 1;
|
||||
const requestedWorkers = Number.parseInt(process.env.OPENCLAW_E2E_WORKERS ?? "", 10);
|
||||
const e2eWorkers =
|
||||
Number.isFinite(requestedWorkers) && requestedWorkers > 0
|
||||
? Math.min(16, requestedWorkers)
|
||||
: defaultWorkers;
|
||||
const verboseE2E = process.env.OPENCLAW_E2E_VERBOSE === "1";
|
||||
|
||||
const baseTestWithProjects =
|
||||
(baseConfig as { test?: { exclude?: string[]; projects?: string[]; setupFiles?: string[] } })
|
||||
.test ?? {};
|
||||
const { projects: _projects, ...baseTest } = baseTestWithProjects as {
|
||||
exclude?: string[];
|
||||
projects?: string[];
|
||||
setupFiles?: string[];
|
||||
};
|
||||
const exclude = (baseTest.exclude ?? []).filter((p) => p !== "**/*.e2e.test.ts");
|
||||
|
||||
export default defineConfig({
|
||||
...base,
|
||||
test: {
|
||||
...baseTest,
|
||||
maxWorkers: e2eWorkers,
|
||||
silent: !verboseE2E,
|
||||
setupFiles: [
|
||||
...new Set(
|
||||
[...(baseTest.setupFiles ?? []), "test/setup-openclaw-runtime.ts"].map(resolveRepoRootPath),
|
||||
),
|
||||
],
|
||||
include: [
|
||||
"test/**/*.e2e.test.ts",
|
||||
"src/**/*.e2e.test.ts",
|
||||
"src/gateway/gateway.test.ts",
|
||||
"src/gateway/server.startup-matrix-migration.integration.test.ts",
|
||||
"src/gateway/sessions-history-http.test.ts",
|
||||
BUNDLED_PLUGIN_E2E_TEST_GLOB,
|
||||
],
|
||||
exclude,
|
||||
},
|
||||
});
|
||||
5
openclaw/test/vitest/vitest.extension-acpx-paths.mjs
Normal file
5
openclaw/test/vitest/vitest.extension-acpx-paths.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const acpxExtensionTestRoots = ["extensions/acpx"];
|
||||
|
||||
export function isAcpxExtensionRoot(root) {
|
||||
return acpxExtensionTestRoots.includes(root);
|
||||
}
|
||||
26
openclaw/test/vitest/vitest.extension-acpx.config.ts
Normal file
26
openclaw/test/vitest/vitest.extension-acpx.config.ts
Normal 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();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export const blueBubblesExtensionTestRoots = ["extensions/bluebubbles"];
|
||||
|
||||
export function isBlueBubblesExtensionRoot(root) {
|
||||
return blueBubblesExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-bluebubbles.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-bluebubbles.config.ts
Normal 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();
|
||||
8
openclaw/test/vitest/vitest.extension-browser.config.ts
Normal file
8
openclaw/test/vitest/vitest.extension-browser.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export default createScopedVitestConfig(["browser/**/*.test.ts"], {
|
||||
dir: "extensions",
|
||||
name: "extension-browser",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
});
|
||||
19
openclaw/test/vitest/vitest.extension-channels.config.ts
Normal file
19
openclaw/test/vitest/vitest.extension-channels.config.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import {
|
||||
extensionChannelOverrideExcludeGlobs,
|
||||
extensionChannelTestInclude,
|
||||
} from "./vitest.channel-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createExtensionChannelsVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(extensionChannelTestInclude, {
|
||||
dir: "extensions",
|
||||
env,
|
||||
exclude: extensionChannelOverrideExcludeGlobs,
|
||||
name: "extension-channels",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createExtensionChannelsVitestConfig();
|
||||
5
openclaw/test/vitest/vitest.extension-diffs-paths.mjs
Normal file
5
openclaw/test/vitest/vitest.extension-diffs-paths.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const diffsExtensionTestRoots = ["extensions/diffs"];
|
||||
|
||||
export function isDiffsExtensionRoot(root) {
|
||||
return diffsExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-diffs.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-diffs.config.ts
Normal 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();
|
||||
9
openclaw/test/vitest/vitest.extension-feishu-paths.mjs
Normal file
9
openclaw/test/vitest/vitest.extension-feishu-paths.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const feishuExtensionIds = ["feishu"];
|
||||
|
||||
export const feishuExtensionTestRoots = feishuExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isFeishuExtensionRoot(root) {
|
||||
return feishuExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-feishu.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-feishu.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { feishuExtensionTestRoots } from "./vitest.extension-feishu-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 createExtensionFeishuVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ??
|
||||
feishuExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-feishu",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionFeishuVitestConfig();
|
||||
5
openclaw/test/vitest/vitest.extension-irc-paths.mjs
Normal file
5
openclaw/test/vitest/vitest.extension-irc-paths.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const ircExtensionTestRoots = ["extensions/irc"];
|
||||
|
||||
export function isIrcExtensionRoot(root) {
|
||||
return ircExtensionTestRoots.includes(root);
|
||||
}
|
||||
26
openclaw/test/vitest/vitest.extension-irc.config.ts
Normal file
26
openclaw/test/vitest/vitest.extension-irc.config.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { ircExtensionTestRoots } from "./vitest.extension-irc-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 createExtensionIrcVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ?? ircExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-irc",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionIrcVitestConfig();
|
||||
9
openclaw/test/vitest/vitest.extension-matrix-paths.mjs
Normal file
9
openclaw/test/vitest/vitest.extension-matrix-paths.mjs
Normal 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);
|
||||
}
|
||||
17
openclaw/test/vitest/vitest.extension-matrix.config.ts
Normal file
17
openclaw/test/vitest/vitest.extension-matrix.config.ts
Normal 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();
|
||||
11
openclaw/test/vitest/vitest.extension-mattermost-paths.mjs
Normal file
11
openclaw/test/vitest/vitest.extension-mattermost-paths.mjs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const mattermostExtensionIds = ["mattermost"];
|
||||
|
||||
export const mattermostExtensionTestRoots = mattermostExtensionIds.map((id) =>
|
||||
bundledPluginRoot(id),
|
||||
);
|
||||
|
||||
export function isMattermostExtensionRoot(root) {
|
||||
return mattermostExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-mattermost.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-mattermost.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { mattermostExtensionTestRoots } from "./vitest.extension-mattermost-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 createExtensionMattermostVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ??
|
||||
mattermostExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-mattermost",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionMattermostVitestConfig();
|
||||
22
openclaw/test/vitest/vitest.extension-media.config.ts
Normal file
22
openclaw/test/vitest/vitest.extension-media.config.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export default createScopedVitestConfig(
|
||||
[
|
||||
"alibaba/**/*.test.ts",
|
||||
"deepgram/**/*.test.ts",
|
||||
"elevenlabs/**/*.test.ts",
|
||||
"fal/**/*.test.ts",
|
||||
"image-generation-core/**/*.test.ts",
|
||||
"runway/**/*.test.ts",
|
||||
"talk-voice/**/*.test.ts",
|
||||
"video-generation-core/**/*.test.ts",
|
||||
"vydra/**/*.test.ts",
|
||||
"xiaomi/**/*.test.ts",
|
||||
],
|
||||
{
|
||||
dir: "extensions",
|
||||
name: "extension-media",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
9
openclaw/test/vitest/vitest.extension-memory-paths.mjs
Normal file
9
openclaw/test/vitest/vitest.extension-memory-paths.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export const memoryExtensionTestRoots = [
|
||||
"extensions/memory-core",
|
||||
"extensions/memory-lancedb",
|
||||
"extensions/memory-wiki",
|
||||
];
|
||||
|
||||
export function isMemoryExtensionRoot(root) {
|
||||
return memoryExtensionTestRoots.includes(root);
|
||||
}
|
||||
28
openclaw/test/vitest/vitest.extension-memory.config.ts
Normal file
28
openclaw/test/vitest/vitest.extension-memory.config.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
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",
|
||||
pool: "forks",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionMemoryVitestConfig();
|
||||
17
openclaw/test/vitest/vitest.extension-messaging-paths.mjs
Normal file
17
openclaw/test/vitest/vitest.extension-messaging-paths.mjs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const messagingExtensionIds = [
|
||||
"googlechat",
|
||||
"nextcloud-talk",
|
||||
"nostr",
|
||||
"qqbot",
|
||||
"synology-chat",
|
||||
"tlon",
|
||||
"twitch",
|
||||
];
|
||||
|
||||
export const messagingExtensionTestRoots = messagingExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isMessagingExtensionRoot(root) {
|
||||
return messagingExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-messaging.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-messaging.config.ts
Normal 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();
|
||||
35
openclaw/test/vitest/vitest.extension-misc.config.ts
Normal file
35
openclaw/test/vitest/vitest.extension-misc.config.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export default createScopedVitestConfig(
|
||||
[
|
||||
"arcee/**/*.test.ts",
|
||||
"brave/**/*.test.ts",
|
||||
"device-pair/**/*.test.ts",
|
||||
"diagnostics-otel/**/*.test.ts",
|
||||
"duckduckgo/**/*.test.ts",
|
||||
"exa/**/*.test.ts",
|
||||
"firecrawl/**/*.test.ts",
|
||||
"fireworks/**/*.test.ts",
|
||||
"kilocode/**/*.test.ts",
|
||||
"litellm/**/*.test.ts",
|
||||
"llm-task/**/*.test.ts",
|
||||
"lobster/**/*.test.ts",
|
||||
"opencode/**/*.test.ts",
|
||||
"opencode-go/**/*.test.ts",
|
||||
"openshell/**/*.test.ts",
|
||||
"perplexity/**/*.test.ts",
|
||||
"phone-control/**/*.test.ts",
|
||||
"searxng/**/*.test.ts",
|
||||
"synthetic/**/*.test.ts",
|
||||
"tavily/**/*.test.ts",
|
||||
"thread-ownership/**/*.test.ts",
|
||||
"vercel-ai-gateway/**/*.test.ts",
|
||||
"webhooks/**/*.test.ts",
|
||||
],
|
||||
{
|
||||
dir: "extensions",
|
||||
name: "extension-misc",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
9
openclaw/test/vitest/vitest.extension-msteams-paths.mjs
Normal file
9
openclaw/test/vitest/vitest.extension-msteams-paths.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const msTeamsExtensionIds = ["msteams"];
|
||||
|
||||
export const msTeamsExtensionTestRoots = msTeamsExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isMsTeamsExtensionRoot(root) {
|
||||
return msTeamsExtensionTestRoots.includes(root);
|
||||
}
|
||||
17
openclaw/test/vitest/vitest.extension-msteams.config.ts
Normal file
17
openclaw/test/vitest/vitest.extension-msteams.config.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { msTeamsExtensionTestRoots } from "./vitest.extension-msteams-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createExtensionMsTeamsVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(
|
||||
msTeamsExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-msteams",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionMsTeamsVitestConfig();
|
||||
40
openclaw/test/vitest/vitest.extension-provider-paths.mjs
Normal file
40
openclaw/test/vitest/vitest.extension-provider-paths.mjs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const providerExtensionIds = [
|
||||
"amazon-bedrock",
|
||||
"amazon-bedrock-mantle",
|
||||
"anthropic",
|
||||
"anthropic-vertex",
|
||||
"byteplus",
|
||||
"chutes",
|
||||
"comfy",
|
||||
"deepseek",
|
||||
"github-copilot",
|
||||
"google",
|
||||
"groq",
|
||||
"huggingface",
|
||||
"kimi-coding",
|
||||
"microsoft",
|
||||
"microsoft-foundry",
|
||||
"minimax",
|
||||
"mistral",
|
||||
"qwen",
|
||||
"moonshot",
|
||||
"nvidia",
|
||||
"ollama",
|
||||
"openai",
|
||||
"openrouter",
|
||||
"qianfan",
|
||||
"stepfun",
|
||||
"together",
|
||||
"venice",
|
||||
"volcengine",
|
||||
"xai",
|
||||
"zai",
|
||||
];
|
||||
|
||||
export const providerExtensionTestRoots = providerExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isProviderExtensionRoot(root) {
|
||||
return providerExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-providers.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-providers.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { providerExtensionTestRoots } from "./vitest.extension-provider-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 createExtensionProvidersVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ??
|
||||
providerExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-providers",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionProvidersVitestConfig();
|
||||
8
openclaw/test/vitest/vitest.extension-qa.config.ts
Normal file
8
openclaw/test/vitest/vitest.extension-qa.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export default createScopedVitestConfig(["qa-channel/**/*.test.ts", "qa-lab/**/*.test.ts"], {
|
||||
dir: "extensions",
|
||||
name: "extension-qa",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
});
|
||||
5
openclaw/test/vitest/vitest.extension-telegram-paths.mjs
Normal file
5
openclaw/test/vitest/vitest.extension-telegram-paths.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const telegramExtensionTestRoots = ["extensions/telegram"];
|
||||
|
||||
export function isTelegramExtensionRoot(root) {
|
||||
return telegramExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-telegram.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-telegram.config.ts
Normal 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();
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const voiceCallExtensionIds = ["voice-call"];
|
||||
|
||||
export const voiceCallExtensionTestRoots = voiceCallExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isVoiceCallExtensionRoot(root) {
|
||||
return voiceCallExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-voice-call.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-voice-call.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { voiceCallExtensionTestRoots } from "./vitest.extension-voice-call-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 createExtensionVoiceCallVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ??
|
||||
voiceCallExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-voice-call",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionVoiceCallVitestConfig();
|
||||
9
openclaw/test/vitest/vitest.extension-whatsapp-paths.mjs
Normal file
9
openclaw/test/vitest/vitest.extension-whatsapp-paths.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { bundledPluginRoot } from "../../scripts/lib/bundled-plugin-paths.mjs";
|
||||
|
||||
export const whatsAppExtensionIds = ["whatsapp"];
|
||||
|
||||
export const whatsAppExtensionTestRoots = whatsAppExtensionIds.map((id) => bundledPluginRoot(id));
|
||||
|
||||
export function isWhatsAppExtensionRoot(root) {
|
||||
return whatsAppExtensionTestRoots.includes(root);
|
||||
}
|
||||
27
openclaw/test/vitest/vitest.extension-whatsapp.config.ts
Normal file
27
openclaw/test/vitest/vitest.extension-whatsapp.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { whatsAppExtensionTestRoots } from "./vitest.extension-whatsapp-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 createExtensionWhatsAppVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ??
|
||||
whatsAppExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-whatsapp",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionWhatsAppVitestConfig();
|
||||
5
openclaw/test/vitest/vitest.extension-zalo-paths.mjs
Normal file
5
openclaw/test/vitest/vitest.extension-zalo-paths.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const zaloExtensionTestRoots = ["extensions/zalo", "extensions/zalouser"];
|
||||
|
||||
export function isZaloExtensionRoot(root) {
|
||||
return zaloExtensionTestRoots.includes(root);
|
||||
}
|
||||
26
openclaw/test/vitest/vitest.extension-zalo.config.ts
Normal file
26
openclaw/test/vitest/vitest.extension-zalo.config.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { zaloExtensionTestRoots } from "./vitest.extension-zalo-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 createExtensionZaloVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ?? zaloExtensionTestRoots.map((root) => `${root}/**/*.test.ts`),
|
||||
{
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extension-zalo",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createExtensionZaloVitestConfig();
|
||||
59
openclaw/test/vitest/vitest.extensions.config.ts
Normal file
59
openclaw/test/vitest/vitest.extensions.config.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
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 { feishuExtensionTestRoots } from "./vitest.extension-feishu-paths.mjs";
|
||||
import { ircExtensionTestRoots } from "./vitest.extension-irc-paths.mjs";
|
||||
import { matrixExtensionTestRoots } from "./vitest.extension-matrix-paths.mjs";
|
||||
import { mattermostExtensionTestRoots } from "./vitest.extension-mattermost-paths.mjs";
|
||||
import { memoryExtensionTestRoots } from "./vitest.extension-memory-paths.mjs";
|
||||
import { messagingExtensionTestRoots } from "./vitest.extension-messaging-paths.mjs";
|
||||
import { msTeamsExtensionTestRoots } from "./vitest.extension-msteams-paths.mjs";
|
||||
import { providerExtensionTestRoots } from "./vitest.extension-provider-paths.mjs";
|
||||
import { telegramExtensionTestRoots } from "./vitest.extension-telegram-paths.mjs";
|
||||
import { voiceCallExtensionTestRoots } from "./vitest.extension-voice-call-paths.mjs";
|
||||
import { whatsAppExtensionTestRoots } from "./vitest.extension-whatsapp-paths.mjs";
|
||||
import { zaloExtensionTestRoots } from "./vitest.extension-zalo-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 createExtensionsVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
) {
|
||||
return createScopedVitestConfig(loadIncludePatternsFromEnv(env) ?? [BUNDLED_PLUGIN_TEST_GLOB], {
|
||||
dir: "extensions",
|
||||
env,
|
||||
name: "extensions",
|
||||
passWithNoTests: true,
|
||||
setupFiles: ["test/setup.extensions.ts"],
|
||||
// Some bundled plugins still run on the channel surface; keep those roots
|
||||
// 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, "")}/**`),
|
||||
...feishuExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...ircExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...matrixExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...mattermostExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...memoryExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...messagingExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...msTeamsExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...providerExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...telegramExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...voiceCallExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...whatsAppExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
...zaloExtensionTestRoots.map((root) => `${root.replace(/^extensions\//u, "")}/**`),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export default createExtensionsVitestConfig();
|
||||
8
openclaw/test/vitest/vitest.full-agentic.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-agentic.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-agentic.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
8
openclaw/test/vitest/vitest.full-auto-reply.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-auto-reply.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-auto-reply.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
8
openclaw/test/vitest/vitest.full-core-bundled.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-core-bundled.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-bundled.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-contracts.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
8
openclaw/test/vitest/vitest.full-core-runtime.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-core-runtime.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-runtime.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-support-boundary.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
11
openclaw/test/vitest/vitest.full-core-unit-fast.config.ts
Normal file
11
openclaw/test/vitest/vitest.full-core-unit-fast.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
|
||||
export default defineConfig({
|
||||
...sharedVitestConfig,
|
||||
test: {
|
||||
...sharedVitestConfig.test,
|
||||
runner: undefined,
|
||||
projects: ["test/vitest/vitest.unit-fast.config.ts"],
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-unit-security.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
8
openclaw/test/vitest/vitest.full-core-unit-src.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-core-unit-src.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-unit-src.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-unit-support.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
8
openclaw/test/vitest/vitest.full-core-unit-ui.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-core-unit-ui.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-core-unit-ui.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
4
openclaw/test/vitest/vitest.full-core-unit.config.ts
Normal file
4
openclaw/test/vitest/vitest.full-core-unit.config.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(fullSuiteVitestShards[0].projects);
|
||||
8
openclaw/test/vitest/vitest.full-extensions.config.ts
Normal file
8
openclaw/test/vitest/vitest.full-extensions.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { createProjectShardVitestConfig } from "./vitest.project-shard-config.ts";
|
||||
import { fullSuiteVitestShards } from "./vitest.test-shards.mjs";
|
||||
|
||||
export default createProjectShardVitestConfig(
|
||||
fullSuiteVitestShards.find(
|
||||
(shard) => shard.config === "test/vitest/vitest.full-extensions.config.ts",
|
||||
)?.projects ?? [],
|
||||
);
|
||||
21
openclaw/test/vitest/vitest.gateway-client.config.ts
Normal file
21
openclaw/test/vitest/vitest.gateway-client.config.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createGatewayClientVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(
|
||||
[
|
||||
"src/gateway/protocol/**/*.test.ts",
|
||||
"src/gateway/**/*client*.test.ts",
|
||||
"src/gateway/**/*reconnect*.test.ts",
|
||||
"src/gateway/**/*android-node*.test.ts",
|
||||
"src/gateway/**/*gateway-cli-backend*.test.ts",
|
||||
],
|
||||
{
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
exclude: ["src/gateway/**/*server*.test.ts"],
|
||||
name: "gateway-client",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createGatewayClientVitestConfig();
|
||||
30
openclaw/test/vitest/vitest.gateway-core.config.ts
Normal file
30
openclaw/test/vitest/vitest.gateway-core.config.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
const nonCoreGatewayTestExclude = [
|
||||
"src/gateway/server-methods/**/*.test.ts",
|
||||
"src/gateway/protocol/**/*.test.ts",
|
||||
"src/gateway/**/*client*.test.ts",
|
||||
"src/gateway/**/*reconnect*.test.ts",
|
||||
"src/gateway/**/*android-node*.test.ts",
|
||||
"src/gateway/**/*gateway-cli-backend*.test.ts",
|
||||
"src/gateway/**/*server*.test.ts",
|
||||
"src/gateway/gateway.test.ts",
|
||||
"src/gateway/embeddings-http.test.ts",
|
||||
"src/gateway/models-http.test.ts",
|
||||
"src/gateway/openai-http.test.ts",
|
||||
"src/gateway/openresponses-http.test.ts",
|
||||
"src/gateway/probe.auth.integration.test.ts",
|
||||
"src/gateway/server.startup-matrix-migration.integration.test.ts",
|
||||
"src/gateway/sessions-history-http.test.ts",
|
||||
];
|
||||
|
||||
export function createGatewayCoreVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/gateway/**/*.test.ts"], {
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
exclude: nonCoreGatewayTestExclude,
|
||||
name: "gateway-core",
|
||||
});
|
||||
}
|
||||
|
||||
export default createGatewayCoreVitestConfig();
|
||||
11
openclaw/test/vitest/vitest.gateway-methods.config.ts
Normal file
11
openclaw/test/vitest/vitest.gateway-methods.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createGatewayMethodsVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/gateway/server-methods/**/*.test.ts"], {
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
name: "gateway-methods",
|
||||
});
|
||||
}
|
||||
|
||||
export default createGatewayMethodsVitestConfig();
|
||||
28
openclaw/test/vitest/vitest.gateway-server.config.ts
Normal file
28
openclaw/test/vitest/vitest.gateway-server.config.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
const gatewayServerBackedHttpTests = [
|
||||
"src/gateway/embeddings-http.test.ts",
|
||||
"src/gateway/models-http.test.ts",
|
||||
"src/gateway/openai-http.test.ts",
|
||||
"src/gateway/openresponses-http.test.ts",
|
||||
"src/gateway/probe.auth.integration.test.ts",
|
||||
];
|
||||
|
||||
export function createGatewayServerVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(
|
||||
["src/gateway/**/*server*.test.ts", ...gatewayServerBackedHttpTests],
|
||||
{
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
exclude: [
|
||||
"src/gateway/server-methods/**/*.test.ts",
|
||||
"src/gateway/gateway.test.ts",
|
||||
"src/gateway/server.startup-matrix-migration.integration.test.ts",
|
||||
"src/gateway/sessions-history-http.test.ts",
|
||||
],
|
||||
name: "gateway-server",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createGatewayServerVitestConfig();
|
||||
16
openclaw/test/vitest/vitest.gateway.config.ts
Normal file
16
openclaw/test/vitest/vitest.gateway.config.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createGatewayVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/gateway/**/*.test.ts"], {
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
exclude: [
|
||||
"src/gateway/gateway.test.ts",
|
||||
"src/gateway/server.startup-matrix-migration.integration.test.ts",
|
||||
"src/gateway/sessions-history-http.test.ts",
|
||||
],
|
||||
name: "gateway",
|
||||
});
|
||||
}
|
||||
|
||||
export default createGatewayVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.hooks.config.ts
Normal file
12
openclaw/test/vitest/vitest.hooks.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createHooksVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/hooks/**/*.test.ts"], {
|
||||
dir: "src/hooks",
|
||||
env,
|
||||
name: "hooks",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createHooksVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.infra.config.ts
Normal file
12
openclaw/test/vitest/vitest.infra.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createInfraVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/infra/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
name: "infra",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createInfraVitestConfig();
|
||||
32
openclaw/test/vitest/vitest.live.config.ts
Normal file
32
openclaw/test/vitest/vitest.live.config.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { BUNDLED_PLUGIN_LIVE_TEST_GLOB } from "./vitest.bundled-plugin-paths.ts";
|
||||
import baseConfig from "./vitest.config.ts";
|
||||
import { resolveRepoRootPath } from "./vitest.shared.config.ts";
|
||||
|
||||
const base = baseConfig as unknown as Record<string, unknown>;
|
||||
const baseTestWithProjects =
|
||||
(baseConfig as { test?: { exclude?: string[]; setupFiles?: string[] } }).test ?? {};
|
||||
const { projects: _projects, ...baseTest } = baseTestWithProjects as {
|
||||
exclude?: string[];
|
||||
projects?: string[];
|
||||
setupFiles?: string[];
|
||||
};
|
||||
const exclude = (baseTest.exclude ?? []).filter((p) => p !== "**/*.live.test.ts");
|
||||
|
||||
export default defineConfig({
|
||||
...base,
|
||||
test: {
|
||||
...baseTest,
|
||||
// Live suites need immediate provider/gateway progress output rather than
|
||||
// Vitest's buffered per-test console capture.
|
||||
disableConsoleIntercept: true,
|
||||
maxWorkers: 1,
|
||||
setupFiles: [
|
||||
...new Set(
|
||||
[...(baseTest.setupFiles ?? []), "test/setup-openclaw-runtime.ts"].map(resolveRepoRootPath),
|
||||
),
|
||||
],
|
||||
include: ["src/**/*.live.test.ts", "test/**/*.live.test.ts", BUNDLED_PLUGIN_LIVE_TEST_GLOB],
|
||||
exclude,
|
||||
},
|
||||
});
|
||||
12
openclaw/test/vitest/vitest.logging.config.ts
Normal file
12
openclaw/test/vitest/vitest.logging.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createLoggingVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/logging/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
name: "logging",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createLoggingVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.media-understanding.config.ts
Normal file
12
openclaw/test/vitest/vitest.media-understanding.config.ts
Normal 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
openclaw/test/vitest/vitest.media.config.ts
Normal file
12
openclaw/test/vitest/vitest.media.config.ts
Normal 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();
|
||||
108
openclaw/test/vitest/vitest.pattern-file.ts
Normal file
108
openclaw/test/vitest/vitest.pattern-file.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
function normalizeCliPattern(value: string): string {
|
||||
let normalized = value
|
||||
.trim()
|
||||
.replace(/^\.\/+/u, "")
|
||||
.replace(/\/+$/u, "");
|
||||
if (
|
||||
/^(?:src|test|extensions|ui|packages|apps)(?:\/|$)/u.test(normalized) &&
|
||||
!/[?*[\]{}]/u.test(normalized) &&
|
||||
!/\.(?:[cm]?[jt]sx?)$/u.test(normalized)
|
||||
) {
|
||||
normalized = `${normalized}/**/*.test.*`;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function looksLikeCliIncludePattern(value: string): boolean {
|
||||
const normalized = normalizeCliPattern(value);
|
||||
return (
|
||||
normalized.includes(".test.") ||
|
||||
normalized.includes(".e2e.") ||
|
||||
normalized.includes(".live.") ||
|
||||
/^(?:src|test|extensions|ui|packages|apps)(?:\/|$)/u.test(normalized)
|
||||
);
|
||||
}
|
||||
|
||||
export function loadPatternListFile(filePath: string, label: string): string[] {
|
||||
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8")) as unknown;
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new TypeError(`${label} must point to a JSON array: ${filePath}`);
|
||||
}
|
||||
return parsed.filter((value): value is string => typeof value === "string" && value.length > 0);
|
||||
}
|
||||
|
||||
export function loadPatternListFromEnv(
|
||||
envKey: string,
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): string[] | null {
|
||||
const filePath = env[envKey]?.trim();
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
return loadPatternListFile(filePath, envKey);
|
||||
}
|
||||
|
||||
export function loadPatternListFromArgv(argv: string[] = process.argv): string[] | null {
|
||||
const optionValueFlags = new Set([
|
||||
"-c",
|
||||
"-r",
|
||||
"-t",
|
||||
"--config",
|
||||
"--dir",
|
||||
"--environment",
|
||||
"--exclude",
|
||||
"--maxWorkers",
|
||||
"--mode",
|
||||
"--outputFile",
|
||||
"--pool",
|
||||
"--project",
|
||||
"--reporter",
|
||||
"--root",
|
||||
"--shard",
|
||||
"--testNamePattern",
|
||||
]);
|
||||
const values: string[] = [];
|
||||
let skipNext = false;
|
||||
for (const value of argv.slice(2)) {
|
||||
if (skipNext) {
|
||||
skipNext = false;
|
||||
continue;
|
||||
}
|
||||
if (value === "run" || value === "watch" || value === "bench") {
|
||||
continue;
|
||||
}
|
||||
if (optionValueFlags.has(value)) {
|
||||
skipNext = true;
|
||||
continue;
|
||||
}
|
||||
if (value.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
const patterns = values.filter(looksLikeCliIncludePattern).map(normalizeCliPattern);
|
||||
|
||||
return patterns.length > 0 ? [...new Set(patterns)] : null;
|
||||
}
|
||||
|
||||
export function narrowIncludePatternsForCli(
|
||||
includePatterns: string[],
|
||||
argv: string[] = process.argv,
|
||||
): string[] | null {
|
||||
const cliPatterns = loadPatternListFromArgv(argv);
|
||||
if (!cliPatterns) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const matched = cliPatterns.filter((value) =>
|
||||
includePatterns.some(
|
||||
(pattern) => path.matchesGlob(value, pattern) || path.matchesGlob(pattern, value),
|
||||
),
|
||||
);
|
||||
|
||||
return [...new Set(matched)];
|
||||
}
|
||||
59
openclaw/test/vitest/vitest.performance-config.ts
Normal file
59
openclaw/test/vitest/vitest.performance-config.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
type EnvMap = Record<string, string | undefined>;
|
||||
|
||||
const isEnabled = (value: string | undefined): boolean => {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
return normalized === "1" || normalized === "true";
|
||||
};
|
||||
|
||||
const isDisabled = (value: string | undefined): boolean => {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
return normalized === "0" || normalized === "false";
|
||||
};
|
||||
|
||||
const isWindowsEnv = (env: EnvMap, platform: NodeJS.Platform): boolean => {
|
||||
if (platform === "win32") {
|
||||
return true;
|
||||
}
|
||||
const runnerOs = env.RUNNER_OS?.trim().toLowerCase();
|
||||
return runnerOs === "windows";
|
||||
};
|
||||
|
||||
type VitestExperimentalConfig = {
|
||||
experimental?: {
|
||||
fsModuleCache?: true;
|
||||
fsModuleCachePath?: string;
|
||||
importDurations?: { print: true };
|
||||
printImportBreakdown?: true;
|
||||
};
|
||||
};
|
||||
|
||||
export function loadVitestExperimentalConfig(
|
||||
env: EnvMap = process.env,
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): VitestExperimentalConfig {
|
||||
const experimental: {
|
||||
fsModuleCache?: true;
|
||||
fsModuleCachePath?: string;
|
||||
importDurations?: { print: true };
|
||||
printImportBreakdown?: true;
|
||||
} = {};
|
||||
const windowsEnv = isWindowsEnv(env, platform);
|
||||
|
||||
if (!windowsEnv && !isDisabled(env.OPENCLAW_VITEST_FS_MODULE_CACHE)) {
|
||||
experimental.fsModuleCache = true;
|
||||
}
|
||||
if (windowsEnv && isEnabled(env.OPENCLAW_VITEST_FS_MODULE_CACHE)) {
|
||||
experimental.fsModuleCache = true;
|
||||
}
|
||||
if (experimental.fsModuleCache && env.OPENCLAW_VITEST_FS_MODULE_CACHE_PATH?.trim()) {
|
||||
experimental.fsModuleCachePath = env.OPENCLAW_VITEST_FS_MODULE_CACHE_PATH.trim();
|
||||
}
|
||||
if (isEnabled(env.OPENCLAW_VITEST_IMPORT_DURATIONS)) {
|
||||
experimental.importDurations = { print: true };
|
||||
}
|
||||
if (isEnabled(env.OPENCLAW_VITEST_PRINT_IMPORT_BREAKDOWN)) {
|
||||
experimental.printImportBreakdown = true;
|
||||
}
|
||||
|
||||
return Object.keys(experimental).length > 0 ? { experimental } : {};
|
||||
}
|
||||
16
openclaw/test/vitest/vitest.plugin-sdk-light.config.ts
Normal file
16
openclaw/test/vitest/vitest.plugin-sdk-light.config.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { pluginSdkLightTestFiles } from "./vitest.plugin-sdk-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { getUnitFastTestFiles } from "./vitest.unit-fast-paths.mjs";
|
||||
|
||||
export function createPluginSdkLightVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(pluginSdkLightTestFiles, {
|
||||
dir: "src",
|
||||
env,
|
||||
exclude: getUnitFastTestFiles(),
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
name: "plugin-sdk-light",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createPluginSdkLightVitestConfig();
|
||||
56
openclaw/test/vitest/vitest.plugin-sdk-paths.mjs
Normal file
56
openclaw/test/vitest/vitest.plugin-sdk-paths.mjs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const normalizeRepoPath = (value) => value.replaceAll("\\", "/");
|
||||
|
||||
const pluginSdkLightEntries = [
|
||||
{ source: "src/plugin-sdk/acp-runtime.ts", test: "src/plugin-sdk/acp-runtime.test.ts" },
|
||||
{ source: "src/plugin-sdk/allow-from.ts", test: "src/plugin-sdk/allow-from.test.ts" },
|
||||
{
|
||||
source: "src/plugin-sdk/keyed-async-queue.ts",
|
||||
test: "src/plugin-sdk/keyed-async-queue.test.ts",
|
||||
},
|
||||
{ source: "src/plugin-sdk/lazy-value.ts", test: "src/plugin-sdk/lazy-value.test.ts" },
|
||||
{
|
||||
source: "src/plugin-sdk/persistent-dedupe.ts",
|
||||
test: "src/plugin-sdk/persistent-dedupe.test.ts",
|
||||
},
|
||||
{ source: "src/plugin-sdk/provider-entry.ts", test: "src/plugin-sdk/provider-entry.test.ts" },
|
||||
{
|
||||
source: "src/plugin-sdk/provider-model-shared.ts",
|
||||
test: "src/plugin-sdk/provider-model-shared.test.ts",
|
||||
},
|
||||
{ source: "src/plugin-sdk/provider-tools.ts", test: "src/plugin-sdk/provider-tools.test.ts" },
|
||||
{
|
||||
source: "src/plugin-sdk/status-helpers.ts",
|
||||
test: "src/plugin-sdk/status-helpers.test.ts",
|
||||
},
|
||||
{ source: "src/plugin-sdk/temp-path.ts", test: "src/plugin-sdk/temp-path.test.ts" },
|
||||
{
|
||||
source: "src/plugin-sdk/text-chunking.ts",
|
||||
test: "src/plugin-sdk/text-chunking.test.ts",
|
||||
},
|
||||
{
|
||||
source: "src/plugin-sdk/webhook-targets.ts",
|
||||
test: "src/plugin-sdk/webhook-targets.test.ts",
|
||||
},
|
||||
];
|
||||
|
||||
const pluginSdkLightIncludePatternByFile = new Map(
|
||||
pluginSdkLightEntries.flatMap(({ source, test }) => [
|
||||
[source, test],
|
||||
[test, test],
|
||||
]),
|
||||
);
|
||||
|
||||
export const pluginSdkLightSourceFiles = pluginSdkLightEntries.map(({ source }) => source);
|
||||
export const pluginSdkLightTestFiles = pluginSdkLightEntries.map(({ test }) => test);
|
||||
|
||||
export function isPluginSdkLightTarget(file) {
|
||||
return pluginSdkLightIncludePatternByFile.has(normalizeRepoPath(file));
|
||||
}
|
||||
|
||||
export function isPluginSdkLightTestFile(file) {
|
||||
return pluginSdkLightTestFiles.includes(normalizeRepoPath(file));
|
||||
}
|
||||
|
||||
export function resolvePluginSdkLightIncludePattern(file) {
|
||||
return pluginSdkLightIncludePatternByFile.get(normalizeRepoPath(file)) ?? null;
|
||||
}
|
||||
14
openclaw/test/vitest/vitest.plugin-sdk.config.ts
Normal file
14
openclaw/test/vitest/vitest.plugin-sdk.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { pluginSdkLightTestFiles } from "./vitest.plugin-sdk-paths.mjs";
|
||||
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,
|
||||
exclude: pluginSdkLightTestFiles,
|
||||
name: "plugin-sdk",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createPluginSdkVitestConfig();
|
||||
14
openclaw/test/vitest/vitest.plugins.config.ts
Normal file
14
openclaw/test/vitest/vitest.plugins.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
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,
|
||||
exclude: ["src/plugins/contracts/**"],
|
||||
isolate: true,
|
||||
name: "plugins",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createPluginsVitestConfig();
|
||||
23
openclaw/test/vitest/vitest.process.config.ts
Normal file
23
openclaw/test/vitest/vitest.process.config.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createProcessVitestConfig(env?: Record<string, string | undefined>) {
|
||||
const config = createScopedVitestConfig(["src/process/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
name: "process",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
return {
|
||||
...config,
|
||||
test: {
|
||||
...config.test,
|
||||
sequence: {
|
||||
...config.test?.sequence,
|
||||
groupOrder: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default createProcessVitestConfig();
|
||||
17
openclaw/test/vitest/vitest.project-shard-config.ts
Normal file
17
openclaw/test/vitest/vitest.project-shard-config.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { nonIsolatedRunnerPath, sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
|
||||
export function createProjectShardVitestConfig(projects: readonly string[]) {
|
||||
const maxWorkers = sharedVitestConfig.test.maxWorkers;
|
||||
if (!process.env.OPENCLAW_VITEST_MAX_WORKERS && typeof maxWorkers === "number") {
|
||||
process.env.OPENCLAW_VITEST_MAX_WORKERS = String(maxWorkers);
|
||||
}
|
||||
return defineConfig({
|
||||
...sharedVitestConfig,
|
||||
test: {
|
||||
...sharedVitestConfig.test,
|
||||
runner: nonIsolatedRunnerPath,
|
||||
projects: [...projects],
|
||||
},
|
||||
});
|
||||
}
|
||||
23
openclaw/test/vitest/vitest.runtime-config.config.ts
Normal file
23
openclaw/test/vitest/vitest.runtime-config.config.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createRuntimeConfigVitestConfig(env?: Record<string, string | undefined>) {
|
||||
const config = createScopedVitestConfig(["src/config/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
name: "runtime-config",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
return {
|
||||
...config,
|
||||
test: {
|
||||
...config.test,
|
||||
sequence: {
|
||||
...config.test?.sequence,
|
||||
groupOrder: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default createRuntimeConfigVitestConfig();
|
||||
207
openclaw/test/vitest/vitest.scoped-config.ts
Normal file
207
openclaw/test/vitest/vitest.scoped-config.ts
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
import path from "node:path";
|
||||
import { defineConfig } from "vitest/config";
|
||||
import { loadPatternListFromEnv, narrowIncludePatternsForCli } from "./vitest.pattern-file.ts";
|
||||
import {
|
||||
nonIsolatedRunnerPath,
|
||||
repoRoot,
|
||||
resolveRepoRootPath,
|
||||
sharedVitestConfig,
|
||||
} from "./vitest.shared.config.ts";
|
||||
import { getUnitFastTestFiles } from "./vitest.unit-fast-paths.mjs";
|
||||
|
||||
function normalizePathPattern(value: string): string {
|
||||
return value.replaceAll("\\", "/");
|
||||
}
|
||||
|
||||
function relativizeScopedPattern(value: string, dir: string): string {
|
||||
const normalizedValue = normalizePathPattern(value);
|
||||
const normalizedDir = normalizePathPattern(dir).replace(/\/+$/u, "");
|
||||
if (!normalizedDir) {
|
||||
return normalizedValue;
|
||||
}
|
||||
if (normalizedValue === normalizedDir) {
|
||||
return ".";
|
||||
}
|
||||
const prefix = `${normalizedDir}/`;
|
||||
return normalizedValue.startsWith(prefix)
|
||||
? normalizedValue.slice(prefix.length)
|
||||
: normalizedValue;
|
||||
}
|
||||
|
||||
function relativizeScopedPatterns(values: string[], dir?: string): string[] {
|
||||
if (!dir) {
|
||||
return values.map(normalizePathPattern);
|
||||
}
|
||||
return values.map((value) => relativizeScopedPattern(value, dir));
|
||||
}
|
||||
|
||||
export function resolveVitestIsolation(
|
||||
_env: Record<string, string | undefined> = process.env,
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SCOPED_PROJECT_GROUP_ORDER_BY_NAME = new Map(
|
||||
[
|
||||
"acp",
|
||||
"agents",
|
||||
"auto-reply",
|
||||
"auto-reply-core",
|
||||
"auto-reply-reply",
|
||||
"auto-reply-top-level",
|
||||
"boundary",
|
||||
"bundled",
|
||||
"channels",
|
||||
"cli",
|
||||
"commands",
|
||||
"commands-light",
|
||||
"cron",
|
||||
"daemon",
|
||||
"extension-acpx",
|
||||
"extension-bluebubbles",
|
||||
"extension-channels",
|
||||
"extension-diffs",
|
||||
"extension-feishu",
|
||||
"extension-irc",
|
||||
"extension-mattermost",
|
||||
"extension-matrix",
|
||||
"extension-memory",
|
||||
"extension-messaging",
|
||||
"extension-msteams",
|
||||
"extension-providers",
|
||||
"extension-telegram",
|
||||
"extension-voice-call",
|
||||
"extension-whatsapp",
|
||||
"extension-zalo",
|
||||
"extensions",
|
||||
"gateway",
|
||||
"hooks",
|
||||
"infra",
|
||||
"logging",
|
||||
"media",
|
||||
"media-understanding",
|
||||
"plugin-sdk",
|
||||
"plugin-sdk-light",
|
||||
"plugins",
|
||||
"process",
|
||||
"runtime-config",
|
||||
"secrets",
|
||||
"shared-core",
|
||||
"tasks",
|
||||
"tooling",
|
||||
"tui",
|
||||
"ui",
|
||||
"unit-fast",
|
||||
"unit-security",
|
||||
"unit-src",
|
||||
"unit-support",
|
||||
"unit-ui",
|
||||
"utils",
|
||||
"wizard",
|
||||
].map((name, index) => [name, index + 10]),
|
||||
);
|
||||
|
||||
function hashFallbackScopedProjectGroupOrder(key: string): number {
|
||||
let hash = 0;
|
||||
for (const char of key) {
|
||||
hash = (hash * 33 + char.charCodeAt(0)) % 10_000;
|
||||
}
|
||||
return hash + 1_000;
|
||||
}
|
||||
|
||||
function resolveScopedProjectGroupOrder(
|
||||
name?: string,
|
||||
dir?: string,
|
||||
include?: string[],
|
||||
): number | undefined {
|
||||
const normalizedName = name?.trim();
|
||||
if (normalizedName) {
|
||||
return (
|
||||
SCOPED_PROJECT_GROUP_ORDER_BY_NAME.get(normalizedName) ??
|
||||
hashFallbackScopedProjectGroupOrder(normalizedName)
|
||||
);
|
||||
}
|
||||
const normalizedInclude = include?.map(normalizePathPattern).join("|") ?? "";
|
||||
const key = [dir?.trim(), normalizedInclude].filter(Boolean).join("|");
|
||||
if (!key) {
|
||||
return undefined;
|
||||
}
|
||||
return hashFallbackScopedProjectGroupOrder(key);
|
||||
}
|
||||
|
||||
export function createScopedVitestConfig(
|
||||
include: string[],
|
||||
options?: {
|
||||
deps?: Record<string, unknown>;
|
||||
dir?: string;
|
||||
env?: Record<string, string | undefined>;
|
||||
environment?: string;
|
||||
exclude?: string[];
|
||||
argv?: string[];
|
||||
includeOpenClawRuntimeSetup?: boolean;
|
||||
isolate?: boolean;
|
||||
name?: string;
|
||||
fileParallelism?: boolean;
|
||||
pool?: "forks" | "threads";
|
||||
passWithNoTests?: boolean;
|
||||
excludeUnitFastTests?: boolean;
|
||||
setupFiles?: string[];
|
||||
useNonIsolatedRunner?: boolean;
|
||||
},
|
||||
) {
|
||||
const base = sharedVitestConfig as Record<string, unknown>;
|
||||
const baseTest = sharedVitestConfig.test ?? {};
|
||||
const scopedDir = options?.dir;
|
||||
const resolvedScopedDir = scopedDir ? path.join(repoRoot, scopedDir) : undefined;
|
||||
const env = options?.env;
|
||||
const includeFromEnv = loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
|
||||
const cliInclude = narrowIncludePatternsForCli(include, options?.argv);
|
||||
const unitFastExcludePatterns =
|
||||
options?.excludeUnitFastTests === false ? [] : getUnitFastTestFiles();
|
||||
const exclude = relativizeScopedPatterns(
|
||||
[...(baseTest.exclude ?? []), ...unitFastExcludePatterns, ...(options?.exclude ?? [])],
|
||||
scopedDir,
|
||||
);
|
||||
const isolate = options?.isolate ?? resolveVitestIsolation(options?.env);
|
||||
const setupFiles = [
|
||||
...new Set([
|
||||
...(baseTest.setupFiles ?? []),
|
||||
...(options?.setupFiles ?? []),
|
||||
...(options?.includeOpenClawRuntimeSetup === false ? [] : ["test/setup-openclaw-runtime.ts"]),
|
||||
]),
|
||||
].map(resolveRepoRootPath);
|
||||
const useNonIsolatedRunner = options?.useNonIsolatedRunner ?? !isolate;
|
||||
const runner = useNonIsolatedRunner ? nonIsolatedRunnerPath : undefined;
|
||||
const scopedGroupOrder = resolveScopedProjectGroupOrder(options?.name, scopedDir, include);
|
||||
|
||||
return defineConfig({
|
||||
...base,
|
||||
test: {
|
||||
...baseTest,
|
||||
...(options?.deps ? { deps: options.deps } : {}),
|
||||
...(options?.name ? { name: options.name } : {}),
|
||||
...(options?.environment ? { environment: options.environment } : {}),
|
||||
isolate,
|
||||
...(runner ? { runner } : { runner: undefined }),
|
||||
setupFiles,
|
||||
...(resolvedScopedDir ? { dir: resolvedScopedDir } : {}),
|
||||
include: relativizeScopedPatterns(includeFromEnv ?? cliInclude ?? include, scopedDir),
|
||||
exclude,
|
||||
...(options?.pool ? { pool: options.pool } : {}),
|
||||
...(options?.fileParallelism === undefined
|
||||
? {}
|
||||
: { fileParallelism: options.fileParallelism }),
|
||||
...(scopedGroupOrder === undefined
|
||||
? {}
|
||||
: {
|
||||
sequence: {
|
||||
...baseTest.sequence,
|
||||
groupOrder: scopedGroupOrder,
|
||||
},
|
||||
}),
|
||||
...(options?.passWithNoTests !== undefined || cliInclude !== null
|
||||
? { passWithNoTests: options?.passWithNoTests ?? true }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
13
openclaw/test/vitest/vitest.secrets.config.ts
Normal file
13
openclaw/test/vitest/vitest.secrets.config.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
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",
|
||||
pool: "forks",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createSecretsVitestConfig();
|
||||
15
openclaw/test/vitest/vitest.shared-core.config.ts
Normal file
15
openclaw/test/vitest/vitest.shared-core.config.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { getUnitFastTestFiles } from "./vitest.unit-fast-paths.mjs";
|
||||
|
||||
export function createSharedCoreVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/shared/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
exclude: getUnitFastTestFiles(),
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
name: "shared-core",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createSharedCoreVitestConfig();
|
||||
315
openclaw/test/vitest/vitest.shared.config.ts
Normal file
315
openclaw/test/vitest/vitest.shared.config.ts
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { pluginSdkSubpaths } from "../../scripts/lib/plugin-sdk-entries.mjs";
|
||||
import {
|
||||
detectVitestHostInfo as detectVitestHostInfoImpl,
|
||||
isCiLikeEnv,
|
||||
resolveLocalVitestMaxWorkers as resolveLocalVitestMaxWorkersImpl,
|
||||
resolveLocalVitestScheduling as resolveLocalVitestSchedulingImpl,
|
||||
} from "../../scripts/lib/vitest-local-scheduling.mjs";
|
||||
import {
|
||||
BUNDLED_PLUGIN_ROOT_DIR,
|
||||
BUNDLED_PLUGIN_TEST_GLOB,
|
||||
} from "./vitest.bundled-plugin-paths.ts";
|
||||
import { loadVitestExperimentalConfig } from "./vitest.performance-config.ts";
|
||||
import { shouldPrintVitestThrottle } from "./vitest.system-load.ts";
|
||||
|
||||
type VitestHostInfo = {
|
||||
cpuCount?: number;
|
||||
loadAverage1m?: number;
|
||||
totalMemoryBytes?: number;
|
||||
};
|
||||
|
||||
export type OpenClawVitestPool = "forks" | "threads";
|
||||
|
||||
export type LocalVitestScheduling = {
|
||||
maxWorkers: number;
|
||||
fileParallelism: boolean;
|
||||
throttledBySystem: boolean;
|
||||
};
|
||||
|
||||
export const jsdomOptimizedDeps = {
|
||||
optimizer: {
|
||||
web: {
|
||||
enabled: true,
|
||||
include: ["lit", "lit-html", "@lit/reactive-element", "marked"] as string[],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function detectVitestHostInfo(): Required<VitestHostInfo> {
|
||||
return detectVitestHostInfoImpl() as Required<VitestHostInfo>;
|
||||
}
|
||||
|
||||
export function resolveLocalVitestMaxWorkers(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
system: VitestHostInfo = detectVitestHostInfo(),
|
||||
pool: OpenClawVitestPool = resolveDefaultVitestPool(env),
|
||||
): number {
|
||||
return resolveLocalVitestMaxWorkersImpl(env, system, pool);
|
||||
}
|
||||
|
||||
export function resolveLocalVitestScheduling(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
system: VitestHostInfo = detectVitestHostInfo(),
|
||||
pool: OpenClawVitestPool = resolveDefaultVitestPool(env),
|
||||
): LocalVitestScheduling {
|
||||
return resolveLocalVitestSchedulingImpl(env, system, pool) as LocalVitestScheduling;
|
||||
}
|
||||
|
||||
export function resolveDefaultVitestPool(
|
||||
_env: Record<string, string | undefined> = process.env,
|
||||
): OpenClawVitestPool {
|
||||
return "threads";
|
||||
}
|
||||
|
||||
export const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
export const nonIsolatedRunnerPath = path.join(repoRoot, "test", "non-isolated-runner.ts");
|
||||
export function resolveRepoRootPath(value: string): string {
|
||||
return path.isAbsolute(value) ? value : path.join(repoRoot, value);
|
||||
}
|
||||
const isCI = isCiLikeEnv(process.env);
|
||||
const isWindows = process.platform === "win32";
|
||||
const defaultPool = resolveDefaultVitestPool();
|
||||
const localScheduling = resolveLocalVitestScheduling(
|
||||
process.env,
|
||||
detectVitestHostInfo(),
|
||||
defaultPool,
|
||||
);
|
||||
const ciWorkers = isWindows ? 2 : 3;
|
||||
|
||||
if (!isCI && localScheduling.throttledBySystem && shouldPrintVitestThrottle(process.env)) {
|
||||
console.error(
|
||||
`[vitest] throttling local workers to ${localScheduling.maxWorkers}${
|
||||
localScheduling.fileParallelism ? "" : " with file parallelism disabled"
|
||||
} because the host already looks busy.`,
|
||||
);
|
||||
}
|
||||
|
||||
export const sharedVitestConfig = {
|
||||
root: repoRoot,
|
||||
envFile: false,
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: "openclaw/extension-api",
|
||||
replacement: path.join(repoRoot, "src", "extensionAPI.ts"),
|
||||
},
|
||||
...pluginSdkSubpaths.map((subpath) => ({
|
||||
find: `openclaw/plugin-sdk/${subpath}`,
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", `${subpath}.ts`),
|
||||
})),
|
||||
...pluginSdkSubpaths.map((subpath) => ({
|
||||
find: `@openclaw/plugin-sdk/${subpath}`,
|
||||
replacement: path.join(repoRoot, "packages", "plugin-sdk", "src", `${subpath}.ts`),
|
||||
})),
|
||||
{
|
||||
find: "openclaw/plugin-sdk",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "index.ts"),
|
||||
},
|
||||
],
|
||||
},
|
||||
test: {
|
||||
dir: repoRoot,
|
||||
testTimeout: 120_000,
|
||||
hookTimeout: isWindows ? 180_000 : 120_000,
|
||||
unstubEnvs: true,
|
||||
unstubGlobals: true,
|
||||
isolate: false,
|
||||
pool: defaultPool,
|
||||
runner: nonIsolatedRunnerPath,
|
||||
maxWorkers: isCI ? ciWorkers : localScheduling.maxWorkers,
|
||||
fileParallelism: isCI ? true : localScheduling.fileParallelism,
|
||||
forceRerunTriggers: [
|
||||
"package.json",
|
||||
"pnpm-lock.yaml",
|
||||
"test/setup.ts",
|
||||
"test/setup.shared.ts",
|
||||
"test/setup.extensions.ts",
|
||||
"test/setup-openclaw-runtime.ts",
|
||||
"test/vitest/vitest.channel-paths.mjs",
|
||||
"test/vitest/vitest.channels.config.ts",
|
||||
"test/vitest/vitest.acp.config.ts",
|
||||
"test/vitest/vitest.boundary.config.ts",
|
||||
"test/vitest/vitest.bundled.config.ts",
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"vitest.config.ts",
|
||||
"test/vitest/vitest.contracts.config.ts",
|
||||
"test/vitest/vitest.cron.config.ts",
|
||||
"test/vitest/vitest.daemon.config.ts",
|
||||
"test/vitest/vitest.e2e.config.ts",
|
||||
"test/vitest/vitest.extension-acpx-paths.mjs",
|
||||
"test/vitest/vitest.extension-acpx.config.ts",
|
||||
"test/vitest/vitest.extension-bluebubbles-paths.mjs",
|
||||
"test/vitest/vitest.extension-bluebubbles.config.ts",
|
||||
"test/vitest/vitest.extension-channels.config.ts",
|
||||
"test/vitest/vitest.extension-diffs-paths.mjs",
|
||||
"test/vitest/vitest.extension-diffs.config.ts",
|
||||
"test/vitest/vitest.extension-feishu-paths.mjs",
|
||||
"test/vitest/vitest.extension-feishu.config.ts",
|
||||
"test/vitest/vitest.extension-irc-paths.mjs",
|
||||
"test/vitest/vitest.extension-irc.config.ts",
|
||||
"test/vitest/vitest.extension-mattermost-paths.mjs",
|
||||
"test/vitest/vitest.extension-mattermost.config.ts",
|
||||
"test/vitest/vitest.extension-matrix-paths.mjs",
|
||||
"test/vitest/vitest.extension-matrix.config.ts",
|
||||
"test/vitest/vitest.extension-memory-paths.mjs",
|
||||
"test/vitest/vitest.extension-memory.config.ts",
|
||||
"test/vitest/vitest.extension-messaging-paths.mjs",
|
||||
"test/vitest/vitest.extension-messaging.config.ts",
|
||||
"test/vitest/vitest.extension-msteams-paths.mjs",
|
||||
"test/vitest/vitest.extension-msteams.config.ts",
|
||||
"test/vitest/vitest.extensions.config.ts",
|
||||
"test/vitest/vitest.gateway.config.ts",
|
||||
"test/vitest/vitest.gateway-core.config.ts",
|
||||
"test/vitest/vitest.gateway-client.config.ts",
|
||||
"test/vitest/vitest.gateway-methods.config.ts",
|
||||
"test/vitest/vitest.gateway-server.config.ts",
|
||||
"test/vitest/vitest.hooks.config.ts",
|
||||
"test/vitest/vitest.infra.config.ts",
|
||||
"test/vitest/vitest.live.config.ts",
|
||||
"test/vitest/vitest.media.config.ts",
|
||||
"test/vitest/vitest.media-understanding.config.ts",
|
||||
"test/vitest/vitest.performance-config.ts",
|
||||
"test/vitest/vitest.unit-fast.config.ts",
|
||||
"test/vitest/vitest.unit-fast-paths.mjs",
|
||||
"test/vitest/vitest.scoped-config.ts",
|
||||
"test/vitest/vitest.shared-core.config.ts",
|
||||
"test/vitest/vitest.shared.config.ts",
|
||||
"test/vitest/vitest.tooling.config.ts",
|
||||
"test/vitest/vitest.tui.config.ts",
|
||||
"test/vitest/vitest.ui.config.ts",
|
||||
"test/vitest/vitest.utils.config.ts",
|
||||
"test/vitest/vitest.unit.config.ts",
|
||||
"test/vitest/vitest.unit-paths.mjs",
|
||||
"test/vitest/vitest.runtime-config.config.ts",
|
||||
"test/vitest/vitest.secrets.config.ts",
|
||||
"test/vitest/vitest.plugin-sdk.config.ts",
|
||||
"test/vitest/vitest.plugins.config.ts",
|
||||
"test/vitest/vitest.extension-telegram-paths.mjs",
|
||||
"test/vitest/vitest.extension-telegram.config.ts",
|
||||
"test/vitest/vitest.extension-voice-call-paths.mjs",
|
||||
"test/vitest/vitest.extension-voice-call.config.ts",
|
||||
"test/vitest/vitest.extension-whatsapp-paths.mjs",
|
||||
"test/vitest/vitest.extension-whatsapp.config.ts",
|
||||
"test/vitest/vitest.extension-zalo-paths.mjs",
|
||||
"test/vitest/vitest.extension-zalo.config.ts",
|
||||
"test/vitest/vitest.extension-provider-paths.mjs",
|
||||
"test/vitest/vitest.extension-providers.config.ts",
|
||||
"test/vitest/vitest.logging.config.ts",
|
||||
"test/vitest/vitest.process.config.ts",
|
||||
"test/vitest/vitest.tasks.config.ts",
|
||||
"test/vitest/vitest.wizard.config.ts",
|
||||
],
|
||||
include: [
|
||||
"src/**/*.test.ts",
|
||||
BUNDLED_PLUGIN_TEST_GLOB,
|
||||
"packages/**/*.test.ts",
|
||||
"test/**/*.test.ts",
|
||||
"ui/src/ui/app-chat.test.ts",
|
||||
"ui/src/ui/chat/**/*.test.ts",
|
||||
"ui/src/ui/views/agents-utils.test.ts",
|
||||
"ui/src/ui/views/channels.test.ts",
|
||||
"ui/src/ui/views/chat.test.ts",
|
||||
"ui/src/ui/views/nodes.devices.test.ts",
|
||||
"ui/src/ui/views/skills.test.ts",
|
||||
"ui/src/ui/views/dreams.test.ts",
|
||||
"ui/src/ui/views/usage-render-details.test.ts",
|
||||
"ui/src/ui/controllers/agents.test.ts",
|
||||
"ui/src/ui/controllers/chat.test.ts",
|
||||
"ui/src/ui/controllers/skills.test.ts",
|
||||
"ui/src/ui/controllers/sessions.test.ts",
|
||||
"ui/src/ui/views/sessions.test.ts",
|
||||
"ui/src/ui/app-tool-stream.node.test.ts",
|
||||
"ui/src/ui/app-gateway.sessions.node.test.ts",
|
||||
"ui/src/ui/chat/slash-command-executor.node.test.ts",
|
||||
],
|
||||
setupFiles: [resolveRepoRootPath("test/setup.ts")],
|
||||
exclude: [
|
||||
"dist/**",
|
||||
"test/fixtures/**",
|
||||
"apps/macos/**",
|
||||
"apps/macos/.build/**",
|
||||
"**/node_modules/**",
|
||||
"**/vendor/**",
|
||||
"dist/OpenClaw.app/**",
|
||||
"**/*.live.test.ts",
|
||||
"**/*.e2e.test.ts",
|
||||
],
|
||||
coverage: {
|
||||
provider: "v8" as const,
|
||||
reporter: ["text", "lcov"],
|
||||
all: false,
|
||||
thresholds: {
|
||||
lines: 70,
|
||||
functions: 70,
|
||||
branches: 55,
|
||||
statements: 70,
|
||||
},
|
||||
include: ["./src/**/*.ts"],
|
||||
exclude: [
|
||||
`${BUNDLED_PLUGIN_ROOT_DIR}/**`,
|
||||
"apps/**",
|
||||
"ui/**",
|
||||
"test/**",
|
||||
"src/**/*.test.ts",
|
||||
"src/entry.ts",
|
||||
"src/index.ts",
|
||||
"src/runtime.ts",
|
||||
"src/channel-web.ts",
|
||||
"src/logging.ts",
|
||||
"src/cli/**",
|
||||
"src/commands/**",
|
||||
"src/daemon/**",
|
||||
"src/hooks/**",
|
||||
"src/macos/**",
|
||||
"src/acp/**",
|
||||
"src/agents/**",
|
||||
"src/channels/**",
|
||||
"src/gateway/**",
|
||||
"src/line/**",
|
||||
"src/media-understanding/**",
|
||||
"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",
|
||||
"src/agents/sandbox.ts",
|
||||
"src/agents/skills-install.ts",
|
||||
"src/agents/pi-tool-definition-adapter.ts",
|
||||
"src/agents/tools/discord-actions*.ts",
|
||||
"src/agents/tools/slack-actions.ts",
|
||||
"src/infra/state-migrations.ts",
|
||||
"src/infra/skills-remote.ts",
|
||||
"src/infra/update-check.ts",
|
||||
"src/infra/ports-inspect.ts",
|
||||
"src/infra/outbound/outbound-session.ts",
|
||||
"src/memory/batch-gemini.ts",
|
||||
"src/gateway/control-ui.ts",
|
||||
"src/gateway/server-bridge.ts",
|
||||
"src/gateway/server-channels.ts",
|
||||
"src/gateway/server-methods/config.ts",
|
||||
"src/gateway/server-methods/send.ts",
|
||||
"src/gateway/server-methods/skills.ts",
|
||||
"src/gateway/server-methods/talk.ts",
|
||||
"src/gateway/server-methods/web.ts",
|
||||
"src/gateway/server-methods/wizard.ts",
|
||||
"src/gateway/call.ts",
|
||||
"src/process/tau-rpc.ts",
|
||||
"src/process/exec.ts",
|
||||
"src/tui/**",
|
||||
"src/wizard/**",
|
||||
"src/browser/**",
|
||||
"src/channels/web/**",
|
||||
"src/webchat/**",
|
||||
"src/gateway/server.ts",
|
||||
"src/gateway/client.ts",
|
||||
"src/gateway/protocol/**",
|
||||
"src/infra/tailscale.ts",
|
||||
],
|
||||
},
|
||||
...loadVitestExperimentalConfig(),
|
||||
},
|
||||
};
|
||||
122
openclaw/test/vitest/vitest.system-load.ts
Normal file
122
openclaw/test/vitest/vitest.system-load.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import { spawnSync } from "node:child_process";
|
||||
|
||||
type EnvMap = Record<string, string | undefined>;
|
||||
|
||||
export type VitestProcessStats = {
|
||||
otherVitestRootCount: number;
|
||||
otherVitestWorkerCount: number;
|
||||
otherVitestCpuPercent: number;
|
||||
};
|
||||
|
||||
type PsResult = {
|
||||
status: number | null;
|
||||
stdout: string;
|
||||
};
|
||||
|
||||
type DetectVitestProcessStatsOptions = {
|
||||
platform?: NodeJS.Platform;
|
||||
selfPid?: number;
|
||||
runPs?: () => PsResult;
|
||||
};
|
||||
|
||||
const EMPTY_VITEST_PROCESS_STATS: VitestProcessStats = {
|
||||
otherVitestRootCount: 0,
|
||||
otherVitestWorkerCount: 0,
|
||||
otherVitestCpuPercent: 0,
|
||||
};
|
||||
|
||||
const BOOLEAN_TRUE_VALUES = new Set(["1", "true"]);
|
||||
|
||||
function isExplicitlyEnabled(value: string | undefined): boolean {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false;
|
||||
}
|
||||
|
||||
function isVitestWorkerArgs(args: string): boolean {
|
||||
return args.includes("/vitest/dist/workers/") || args.includes("\\vitest\\dist\\workers\\");
|
||||
}
|
||||
|
||||
function isVitestRootArgs(args: string): boolean {
|
||||
return (
|
||||
args.includes("node_modules/.bin/vitest") ||
|
||||
/\bvitest(?:\.(?:m?js|cmd|exe))?\b/u.test(args) ||
|
||||
args.includes("scripts/test-projects.mjs") ||
|
||||
args.includes("scripts/run-vitest.mjs")
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeCpu(rawCpu: string): number {
|
||||
const parsed = Number.parseFloat(rawCpu);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
||||
}
|
||||
|
||||
export function parseVitestProcessStats(
|
||||
psOutput: string,
|
||||
selfPid: number = process.pid,
|
||||
): VitestProcessStats {
|
||||
const stats = { ...EMPTY_VITEST_PROCESS_STATS };
|
||||
|
||||
for (const line of psOutput.split("\n")) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = /^(\d+)\s+([0-9.]+)\s+(.*)$/u.exec(trimmed);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const [, rawPid, rawCpu, args] = match;
|
||||
const pid = Number.parseInt(rawPid, 10);
|
||||
if (!Number.isFinite(pid) || pid === selfPid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isVitestWorkerArgs(args) && !isVitestRootArgs(args)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stats.otherVitestCpuPercent += normalizeCpu(rawCpu);
|
||||
if (isVitestWorkerArgs(args)) {
|
||||
stats.otherVitestWorkerCount += 1;
|
||||
} else {
|
||||
stats.otherVitestRootCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
stats.otherVitestCpuPercent = Number.parseFloat(stats.otherVitestCpuPercent.toFixed(1));
|
||||
return stats;
|
||||
}
|
||||
|
||||
export function detectVitestProcessStats(
|
||||
env: EnvMap = process.env,
|
||||
options: DetectVitestProcessStatsOptions = {},
|
||||
): VitestProcessStats {
|
||||
const platform = options.platform ?? process.platform;
|
||||
if (platform === "win32") {
|
||||
return { ...EMPTY_VITEST_PROCESS_STATS };
|
||||
}
|
||||
|
||||
if (isExplicitlyEnabled(env.OPENCLAW_VITEST_DISABLE_SYSTEM_THROTTLE)) {
|
||||
return { ...EMPTY_VITEST_PROCESS_STATS };
|
||||
}
|
||||
|
||||
const result =
|
||||
options.runPs?.() ??
|
||||
spawnSync("ps", ["-xao", "pid=,pcpu=,args="], {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
});
|
||||
|
||||
if (result.status === 0 && typeof result.stdout === "string" && result.stdout.length > 0) {
|
||||
return parseVitestProcessStats(result.stdout, options.selfPid ?? process.pid);
|
||||
}
|
||||
|
||||
return { ...EMPTY_VITEST_PROCESS_STATS };
|
||||
}
|
||||
|
||||
export function shouldPrintVitestThrottle(env: EnvMap = process.env): boolean {
|
||||
const normalized = env.OPENCLAW_VITEST_PRINT_SYSTEM_THROTTLE?.trim().toLowerCase();
|
||||
return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false;
|
||||
}
|
||||
25
openclaw/test/vitest/vitest.tasks.config.ts
Normal file
25
openclaw/test/vitest/vitest.tasks.config.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createTasksVitestConfig(env?: Record<string, string | undefined>) {
|
||||
const config = createScopedVitestConfig(["src/tasks/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
name: "tasks",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
// Task tests mutate process.env and shared singleton registries/state dirs.
|
||||
// Keep files serialized so temp-dir-backed sqlite stores do not fight each
|
||||
// other under the non-isolated runner.
|
||||
config.test = {
|
||||
...config.test,
|
||||
maxWorkers: 1,
|
||||
fileParallelism: false,
|
||||
sequence: {
|
||||
...config.test?.sequence,
|
||||
groupOrder: 1,
|
||||
},
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
export default createTasksVitestConfig();
|
||||
126
openclaw/test/vitest/vitest.test-shards.mjs
Normal file
126
openclaw/test/vitest/vitest.test-shards.mjs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
export const autoReplyCoreTestInclude = ["src/auto-reply/*.test.ts"];
|
||||
|
||||
export const autoReplyCoreTestExclude = ["src/auto-reply/reply*.test.ts"];
|
||||
|
||||
export const autoReplyTopLevelReplyTestInclude = ["src/auto-reply/reply*.test.ts"];
|
||||
|
||||
export const autoReplyReplySubtreeTestInclude = ["src/auto-reply/reply/**/*.test.ts"];
|
||||
|
||||
export const fullSuiteVitestShards = [
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-unit-fast.config.ts",
|
||||
name: "core-unit-fast",
|
||||
projects: ["test/vitest/vitest.unit-fast.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-unit-src.config.ts",
|
||||
name: "core-unit-src",
|
||||
projects: ["test/vitest/vitest.unit-src.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-unit-security.config.ts",
|
||||
name: "core-unit-security",
|
||||
projects: ["test/vitest/vitest.unit-security.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-unit-ui.config.ts",
|
||||
name: "core-unit-ui",
|
||||
projects: ["test/vitest/vitest.unit-ui.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-unit-support.config.ts",
|
||||
name: "core-unit-support",
|
||||
projects: ["test/vitest/vitest.unit-support.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-support-boundary.config.ts",
|
||||
name: "core-support-boundary",
|
||||
projects: ["test/vitest/vitest.boundary.config.ts", "test/vitest/vitest.tooling.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-contracts.config.ts",
|
||||
name: "core-contracts",
|
||||
projects: ["test/vitest/vitest.contracts.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-bundled.config.ts",
|
||||
name: "core-bundled",
|
||||
projects: ["test/vitest/vitest.bundled.config.ts"],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-core-runtime.config.ts",
|
||||
name: "core-runtime",
|
||||
projects: [
|
||||
"test/vitest/vitest.infra.config.ts",
|
||||
"test/vitest/vitest.hooks.config.ts",
|
||||
"test/vitest/vitest.acp.config.ts",
|
||||
"test/vitest/vitest.runtime-config.config.ts",
|
||||
"test/vitest/vitest.secrets.config.ts",
|
||||
"test/vitest/vitest.logging.config.ts",
|
||||
"test/vitest/vitest.process.config.ts",
|
||||
"test/vitest/vitest.cron.config.ts",
|
||||
"test/vitest/vitest.media.config.ts",
|
||||
"test/vitest/vitest.media-understanding.config.ts",
|
||||
"test/vitest/vitest.shared-core.config.ts",
|
||||
"test/vitest/vitest.tasks.config.ts",
|
||||
"test/vitest/vitest.tui.config.ts",
|
||||
"test/vitest/vitest.ui.config.ts",
|
||||
"test/vitest/vitest.utils.config.ts",
|
||||
"test/vitest/vitest.wizard.config.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-agentic.config.ts",
|
||||
name: "agentic",
|
||||
projects: [
|
||||
"test/vitest/vitest.gateway-core.config.ts",
|
||||
"test/vitest/vitest.gateway-client.config.ts",
|
||||
"test/vitest/vitest.gateway-methods.config.ts",
|
||||
"test/vitest/vitest.gateway-server.config.ts",
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
"test/vitest/vitest.commands.config.ts",
|
||||
"test/vitest/vitest.agents.config.ts",
|
||||
"test/vitest/vitest.daemon.config.ts",
|
||||
"test/vitest/vitest.plugin-sdk-light.config.ts",
|
||||
"test/vitest/vitest.plugin-sdk.config.ts",
|
||||
"test/vitest/vitest.plugins.config.ts",
|
||||
"test/vitest/vitest.channels.config.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-auto-reply.config.ts",
|
||||
name: "auto-reply",
|
||||
projects: [
|
||||
"test/vitest/vitest.auto-reply-core.config.ts",
|
||||
"test/vitest/vitest.auto-reply-top-level.config.ts",
|
||||
"test/vitest/vitest.auto-reply-reply.config.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.full-extensions.config.ts",
|
||||
name: "extensions",
|
||||
projects: [
|
||||
"test/vitest/vitest.extension-acpx.config.ts",
|
||||
"test/vitest/vitest.extension-bluebubbles.config.ts",
|
||||
"test/vitest/vitest.extension-channels.config.ts",
|
||||
"test/vitest/vitest.extension-diffs.config.ts",
|
||||
"test/vitest/vitest.extension-feishu.config.ts",
|
||||
"test/vitest/vitest.extension-irc.config.ts",
|
||||
"test/vitest/vitest.extension-mattermost.config.ts",
|
||||
"test/vitest/vitest.extension-matrix.config.ts",
|
||||
"test/vitest/vitest.extension-memory.config.ts",
|
||||
"test/vitest/vitest.extension-messaging.config.ts",
|
||||
"test/vitest/vitest.extension-msteams.config.ts",
|
||||
"test/vitest/vitest.extension-providers.config.ts",
|
||||
"test/vitest/vitest.extension-telegram.config.ts",
|
||||
"test/vitest/vitest.extension-voice-call.config.ts",
|
||||
"test/vitest/vitest.extension-whatsapp.config.ts",
|
||||
"test/vitest/vitest.extension-zalo.config.ts",
|
||||
"test/vitest/vitest.extension-browser.config.ts",
|
||||
"test/vitest/vitest.extension-qa.config.ts",
|
||||
"test/vitest/vitest.extension-media.config.ts",
|
||||
"test/vitest/vitest.extension-misc.config.ts",
|
||||
],
|
||||
},
|
||||
];
|
||||
27
openclaw/test/vitest/vitest.tooling.config.ts
Normal file
27
openclaw/test/vitest/vitest.tooling.config.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
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 createToolingVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(
|
||||
loadIncludePatternsFromEnv(env) ?? [
|
||||
"test/**/*.test.ts",
|
||||
"src/scripts/**/*.test.ts",
|
||||
"src/config/doc-baseline.integration.test.ts",
|
||||
"src/config/schema.base.generated.test.ts",
|
||||
"src/config/schema.help.quality.test.ts",
|
||||
],
|
||||
{
|
||||
env,
|
||||
name: "tooling",
|
||||
passWithNoTests: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default createToolingVitestConfig();
|
||||
12
openclaw/test/vitest/vitest.tui.config.ts
Normal file
12
openclaw/test/vitest/vitest.tui.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createTuiVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["src/tui/**/*.test.ts"], {
|
||||
dir: "src",
|
||||
env,
|
||||
name: "tui",
|
||||
passWithNoTests: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default createTuiVitestConfig();
|
||||
33
openclaw/test/vitest/vitest.ui.config.ts
Normal file
33
openclaw/test/vitest/vitest.ui.config.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
import { jsdomOptimizedDeps } from "./vitest.shared.config.ts";
|
||||
|
||||
export const unitUiIncludePatterns = [
|
||||
"ui/src/ui/app-chat.test.ts",
|
||||
"ui/src/ui/chat/**/*.test.ts",
|
||||
"ui/src/ui/views/agents-utils.test.ts",
|
||||
"ui/src/ui/views/channels.test.ts",
|
||||
"ui/src/ui/views/chat.test.ts",
|
||||
"ui/src/ui/views/dreams.test.ts",
|
||||
"ui/src/ui/views/usage-render-details.test.ts",
|
||||
"ui/src/ui/controllers/agents.test.ts",
|
||||
"ui/src/ui/controllers/chat.test.ts",
|
||||
];
|
||||
|
||||
export function createUiVitestConfig(
|
||||
env?: Record<string, string | undefined>,
|
||||
options?: { includePatterns?: string[]; name?: string },
|
||||
) {
|
||||
return createScopedVitestConfig(options?.includePatterns ?? ["ui/src/ui/**/*.test.ts"], {
|
||||
deps: jsdomOptimizedDeps,
|
||||
dir: "ui/src/ui",
|
||||
environment: "jsdom",
|
||||
env,
|
||||
excludeUnitFastTests: false,
|
||||
includeOpenClawRuntimeSetup: false,
|
||||
isolate: true,
|
||||
name: options?.name ?? "ui",
|
||||
setupFiles: ["ui/src/test-helpers/lit-warnings.setup.ts"],
|
||||
});
|
||||
}
|
||||
|
||||
export default createUiVitestConfig();
|
||||
268
openclaw/test/vitest/vitest.unit-fast-paths.mjs
Normal file
268
openclaw/test/vitest/vitest.unit-fast-paths.mjs
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
commandsLightSourceFiles,
|
||||
commandsLightTestFiles,
|
||||
} from "./vitest.commands-light-paths.mjs";
|
||||
import { pluginSdkLightSourceFiles, pluginSdkLightTestFiles } from "./vitest.plugin-sdk-paths.mjs";
|
||||
|
||||
const normalizeRepoPath = (value) => value.replaceAll("\\", "/");
|
||||
|
||||
const unitFastCandidateGlobs = [
|
||||
"packages/memory-host-sdk/**/*.test.ts",
|
||||
"packages/plugin-package-contract/**/*.test.ts",
|
||||
"src/acp/**/*.test.ts",
|
||||
"src/agents/**/*.test.ts",
|
||||
"src/auto-reply/**/*.test.ts",
|
||||
"src/bootstrap/**/*.test.ts",
|
||||
"src/channels/**/*.test.ts",
|
||||
"src/cli/**/*.test.ts",
|
||||
"src/commands/**/*.test.ts",
|
||||
"src/config/**/*.test.ts",
|
||||
"src/daemon/**/*.test.ts",
|
||||
"src/i18n/**/*.test.ts",
|
||||
"src/hooks/**/*.test.ts",
|
||||
"src/image-generation/**/*.test.ts",
|
||||
"src/infra/**/*.test.ts",
|
||||
"src/interactive/**/*.test.ts",
|
||||
"src/link-understanding/**/*.test.ts",
|
||||
"src/logging/**/*.test.ts",
|
||||
"src/markdown/**/*.test.ts",
|
||||
"src/media/**/*.test.ts",
|
||||
"src/media-generation/**/*.test.ts",
|
||||
"src/media-understanding/**/*.test.ts",
|
||||
"src/memory-host-sdk/**/*.test.ts",
|
||||
"src/music-generation/**/*.test.ts",
|
||||
"src/node-host/**/*.test.ts",
|
||||
"src/plugin-sdk/**/*.test.ts",
|
||||
"src/plugins/**/*.test.ts",
|
||||
"src/poll-params.test.ts",
|
||||
"src/polls.test.ts",
|
||||
"src/process/**/*.test.ts",
|
||||
"src/routing/**/*.test.ts",
|
||||
"src/sessions/**/*.test.ts",
|
||||
"src/shared/**/*.test.ts",
|
||||
"src/terminal/**/*.test.ts",
|
||||
"src/test-utils/**/*.test.ts",
|
||||
"src/tasks/**/*.test.ts",
|
||||
"src/tts/**/*.test.ts",
|
||||
"src/utils/**/*.test.ts",
|
||||
"src/video-generation/**/*.test.ts",
|
||||
"src/wizard/**/*.test.ts",
|
||||
"test/**/*.test.ts",
|
||||
];
|
||||
const unitFastCandidateExactFiles = [...pluginSdkLightTestFiles, ...commandsLightTestFiles];
|
||||
const broadUnitFastCandidateGlobs = [
|
||||
"src/**/*.test.ts",
|
||||
"packages/**/*.test.ts",
|
||||
"test/**/*.test.ts",
|
||||
];
|
||||
const broadUnitFastCandidateSkipGlobs = [
|
||||
"**/*.e2e.test.ts",
|
||||
"**/*.live.test.ts",
|
||||
"test/fixtures/**/*.test.ts",
|
||||
"test/setup-home-isolation.test.ts",
|
||||
"src/agents/sandbox.resolveSandboxContext.test.ts",
|
||||
"src/channels/plugins/contracts/**/*.test.ts",
|
||||
"src/config/**/*.test.ts",
|
||||
"src/gateway/**/*.test.ts",
|
||||
"src/media-generation/**/*.contract.test.ts",
|
||||
"src/plugins/contracts/**/*.test.ts",
|
||||
"src/plugin-sdk/browser-subpaths.test.ts",
|
||||
"src/security/**/*.test.ts",
|
||||
"src/secrets/**/*.test.ts",
|
||||
];
|
||||
|
||||
const disqualifyingPatterns = [
|
||||
{
|
||||
code: "jsdom-environment",
|
||||
pattern: /@vitest-environment\s+jsdom/u,
|
||||
},
|
||||
{
|
||||
code: "module-mocking",
|
||||
pattern: /\bvi\.(?:mock|doMock|unmock|doUnmock|importActual|resetModules)\s*\(/u,
|
||||
},
|
||||
{
|
||||
code: "module-mocking-helper",
|
||||
pattern: /runtime-module-mocks/u,
|
||||
},
|
||||
{
|
||||
code: "vitest-mock-api",
|
||||
pattern: /\bvi\b/u,
|
||||
},
|
||||
{
|
||||
code: "dynamic-import",
|
||||
pattern: /\b(?:await\s+)?import\s*\(/u,
|
||||
},
|
||||
{
|
||||
code: "fake-timers",
|
||||
pattern:
|
||||
/\bvi\.(?:useFakeTimers|setSystemTime|advanceTimers|runAllTimers|runOnlyPendingTimers)\s*\(/u,
|
||||
},
|
||||
{
|
||||
code: "env-or-global-stub",
|
||||
pattern: /\bvi\.(?:stubEnv|stubGlobal|unstubAllEnvs|unstubAllGlobals)\s*\(/u,
|
||||
},
|
||||
{
|
||||
code: "process-env-mutation",
|
||||
pattern: /(?:process\.env(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])?\s*=|delete\s+process\.env)/u,
|
||||
},
|
||||
{
|
||||
code: "global-mutation",
|
||||
pattern: /(?:globalThis|global)\s*\[[^\]]+\]\s*=/u,
|
||||
},
|
||||
{
|
||||
code: "filesystem-state",
|
||||
pattern:
|
||||
/\b(?:mkdtemp|rmSync|writeFileSync|appendFileSync|mkdirSync|createTemp|makeTempDir|tempDir|tmpdir|node:fs|node:os)\b/u,
|
||||
},
|
||||
{
|
||||
code: "runtime-singleton-state",
|
||||
pattern: /\b(?:setActivePluginRegistry|resetPluginRuntimeStateForTest|reset.*ForTest)\s*\(/u,
|
||||
},
|
||||
];
|
||||
|
||||
function matchesAnyGlob(file, patterns) {
|
||||
return patterns.some((pattern) => path.matchesGlob(file, pattern));
|
||||
}
|
||||
|
||||
function walkFiles(directory, files = []) {
|
||||
let entries;
|
||||
try {
|
||||
entries = fs.readdirSync(directory, { withFileTypes: true });
|
||||
} catch {
|
||||
return files;
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
const entryPath = path.join(directory, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "vendor") {
|
||||
continue;
|
||||
}
|
||||
walkFiles(entryPath, files);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && entry.name.endsWith(".test.ts")) {
|
||||
files.push(normalizeRepoPath(entryPath));
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
export function classifyUnitFastTestFileContent(source) {
|
||||
const reasons = [];
|
||||
for (const { code, pattern } of disqualifyingPatterns) {
|
||||
if (pattern.test(source)) {
|
||||
reasons.push(code);
|
||||
}
|
||||
}
|
||||
return reasons;
|
||||
}
|
||||
|
||||
export function collectUnitFastTestCandidates(cwd = process.cwd()) {
|
||||
const discovered = ["src", "packages", "test"]
|
||||
.flatMap((directory) => walkFiles(path.join(cwd, directory)))
|
||||
.map((file) => normalizeRepoPath(path.relative(cwd, file)))
|
||||
.filter(
|
||||
(file) =>
|
||||
matchesAnyGlob(file, unitFastCandidateGlobs) &&
|
||||
!matchesAnyGlob(file, broadUnitFastCandidateSkipGlobs),
|
||||
);
|
||||
return [...new Set([...discovered, ...unitFastCandidateExactFiles])].toSorted((a, b) =>
|
||||
a.localeCompare(b),
|
||||
);
|
||||
}
|
||||
|
||||
export function collectBroadUnitFastTestCandidates(cwd = process.cwd()) {
|
||||
const discovered = ["src", "packages", "test"]
|
||||
.flatMap((directory) => walkFiles(path.join(cwd, directory)))
|
||||
.map((file) => normalizeRepoPath(path.relative(cwd, file)))
|
||||
.filter(
|
||||
(file) =>
|
||||
matchesAnyGlob(file, broadUnitFastCandidateGlobs) &&
|
||||
!matchesAnyGlob(file, broadUnitFastCandidateSkipGlobs),
|
||||
);
|
||||
return [...new Set([...discovered, ...unitFastCandidateExactFiles])].toSorted((a, b) =>
|
||||
a.localeCompare(b),
|
||||
);
|
||||
}
|
||||
|
||||
export function collectUnitFastTestFileAnalysis(cwd = process.cwd(), options = {}) {
|
||||
const candidates =
|
||||
options.scope === "broad"
|
||||
? collectBroadUnitFastTestCandidates(cwd)
|
||||
: collectUnitFastTestCandidates(cwd);
|
||||
return candidates.map((file) => {
|
||||
const absolutePath = path.join(cwd, file);
|
||||
let source = "";
|
||||
try {
|
||||
source = fs.readFileSync(absolutePath, "utf8");
|
||||
} catch {
|
||||
return {
|
||||
file,
|
||||
unitFast: false,
|
||||
reasons: ["missing-file"],
|
||||
};
|
||||
}
|
||||
const reasons = classifyUnitFastTestFileContent(source);
|
||||
return {
|
||||
file,
|
||||
unitFast: reasons.length === 0,
|
||||
reasons,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
let cachedUnitFastTestFiles = null;
|
||||
let cachedUnitFastTestFileSet = null;
|
||||
let cachedSourceToUnitFastTestFile = null;
|
||||
|
||||
export function getUnitFastTestFiles() {
|
||||
if (cachedUnitFastTestFiles !== null) {
|
||||
return cachedUnitFastTestFiles;
|
||||
}
|
||||
cachedUnitFastTestFiles = collectUnitFastTestFileAnalysis()
|
||||
.filter((entry) => entry.unitFast)
|
||||
.map((entry) => entry.file);
|
||||
return cachedUnitFastTestFiles;
|
||||
}
|
||||
|
||||
function getUnitFastTestFileSet() {
|
||||
if (cachedUnitFastTestFileSet !== null) {
|
||||
return cachedUnitFastTestFileSet;
|
||||
}
|
||||
cachedUnitFastTestFileSet = new Set(getUnitFastTestFiles());
|
||||
return cachedUnitFastTestFileSet;
|
||||
}
|
||||
|
||||
function getSourceToUnitFastTestFile() {
|
||||
if (cachedSourceToUnitFastTestFile !== null) {
|
||||
return cachedSourceToUnitFastTestFile;
|
||||
}
|
||||
const unitFastTestFileSet = getUnitFastTestFileSet();
|
||||
cachedSourceToUnitFastTestFile = new Map(
|
||||
[...pluginSdkLightSourceFiles, ...commandsLightSourceFiles].flatMap((sourceFile) => {
|
||||
const testFile = sourceFile.replace(/\.ts$/u, ".test.ts");
|
||||
return unitFastTestFileSet.has(testFile) ? [[sourceFile, testFile]] : [];
|
||||
}),
|
||||
);
|
||||
return cachedSourceToUnitFastTestFile;
|
||||
}
|
||||
|
||||
export function isUnitFastTestFile(file) {
|
||||
return getUnitFastTestFileSet().has(normalizeRepoPath(file));
|
||||
}
|
||||
|
||||
export function resolveUnitFastTestIncludePattern(file) {
|
||||
const normalized = normalizeRepoPath(file);
|
||||
const unitFastTestFileSet = getUnitFastTestFileSet();
|
||||
if (unitFastTestFileSet.has(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const siblingTestFile = normalized.replace(/\.ts$/u, ".test.ts");
|
||||
if (unitFastTestFileSet.has(siblingTestFile)) {
|
||||
return siblingTestFile;
|
||||
}
|
||||
return getSourceToUnitFastTestFile().get(normalized) ?? null;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue