diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdb3920a8e8..483f970caa2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1183,6 +1183,7 @@ jobs: NODE_OPTIONS: --max-old-space-size=6144 OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }} OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }} + OPENCLAW_TEST_PROJECTS_PARALLEL: "2" shell: bash run: | set -euo pipefail @@ -1190,7 +1191,6 @@ jobs: import { spawnSync } from "node:child_process"; import { writeFileSync } from "node:fs"; import { join } from "node:path"; - import { resolveVitestCliEntry, resolveVitestNodeArgs } from "./scripts/run-vitest.mjs"; const configs = JSON.parse(process.env.OPENCLAW_NODE_TEST_CONFIGS_JSON ?? "[]"); if (!Array.isArray(configs) || configs.length === 0) { @@ -1208,27 +1208,12 @@ jobs: childEnv.OPENCLAW_VITEST_INCLUDE_FILE = includeFile; } - for (const config of configs) { - console.error(`[test] starting ${config}`); - const result = spawnSync( - "pnpm", - [ - "exec", - "node", - ...resolveVitestNodeArgs(process.env), - resolveVitestCliEntry(), - "run", - "--config", - config, - ], - { - env: childEnv, - stdio: "inherit", - }, - ); - if ((result.status ?? 1) !== 0) { - process.exit(result.status ?? 1); - } + const result = spawnSync("pnpm", ["exec", "node", "scripts/test-projects.mjs", ...configs], { + env: childEnv, + stdio: "inherit", + }); + if ((result.status ?? 1) !== 0) { + process.exit(result.status ?? 1); } EOF diff --git a/scripts/test-projects.mjs b/scripts/test-projects.mjs index 87a1a525ab2..4bc0f675d84 100644 --- a/scripts/test-projects.mjs +++ b/scripts/test-projects.mjs @@ -372,7 +372,12 @@ async function main() { targetArgs.length === 0 && changedTargetArgs === null && !runSpecs.some((spec) => spec.watchMode); - const isParallelShardRun = isFullSuiteRun || isFullExtensionsProjectRun(runSpecs); + const isExplicitParallelMultiConfigRun = + Boolean(process.env.OPENCLAW_TEST_PROJECTS_PARALLEL) && + runSpecs.length > 1 && + !runSpecs.some((spec) => spec.watchMode); + const isParallelShardRun = + isFullSuiteRun || isFullExtensionsProjectRun(runSpecs) || isExplicitParallelMultiConfigRun; if (isParallelShardRun) { const concurrency = resolveParallelFullSuiteConcurrency(runSpecs.length, process.env); if (concurrency > 1) { diff --git a/scripts/test-projects.test-support.mjs b/scripts/test-projects.test-support.mjs index 507c065c04e..6ea75fae636 100644 --- a/scripts/test-projects.test-support.mjs +++ b/scripts/test-projects.test-support.mjs @@ -46,7 +46,10 @@ import { resolveVitestCliEntry, resolveVitestNodeArgs } from "./run-vitest.mjs"; const DEFAULT_VITEST_CONFIG = "test/vitest/vitest.unit.config.ts"; const AGENTS_VITEST_CONFIG = "test/vitest/vitest.agents.config.ts"; const ACP_VITEST_CONFIG = "test/vitest/vitest.acp.config.ts"; +const AUTO_REPLY_CORE_VITEST_CONFIG = "test/vitest/vitest.auto-reply-core.config.ts"; const AUTO_REPLY_VITEST_CONFIG = "test/vitest/vitest.auto-reply.config.ts"; +const AUTO_REPLY_REPLY_VITEST_CONFIG = "test/vitest/vitest.auto-reply-reply.config.ts"; +const AUTO_REPLY_TOP_LEVEL_VITEST_CONFIG = "test/vitest/vitest.auto-reply-top-level.config.ts"; const BOUNDARY_VITEST_CONFIG = "test/vitest/vitest.boundary.config.ts"; const BUNDLED_VITEST_CONFIG = "test/vitest/vitest.bundled.config.ts"; const CHANNEL_VITEST_CONFIG = "test/vitest/vitest.channels.config.ts"; @@ -93,6 +96,10 @@ const EXTENSION_WHATSAPP_VITEST_CONFIG = "test/vitest/vitest.extension-whatsapp. const EXTENSION_ZALO_VITEST_CONFIG = "test/vitest/vitest.extension-zalo.config.ts"; const EXTENSIONS_VITEST_CONFIG = "test/vitest/vitest.extensions.config.ts"; const FULL_EXTENSIONS_VITEST_CONFIG = "test/vitest/vitest.full-extensions.config.ts"; +const GATEWAY_CLIENT_VITEST_CONFIG = "test/vitest/vitest.gateway-client.config.ts"; +const GATEWAY_CORE_VITEST_CONFIG = "test/vitest/vitest.gateway-core.config.ts"; +const GATEWAY_METHODS_VITEST_CONFIG = "test/vitest/vitest.gateway-methods.config.ts"; +const GATEWAY_SERVER_VITEST_CONFIG = "test/vitest/vitest.gateway-server.config.ts"; const GATEWAY_VITEST_CONFIG = "test/vitest/vitest.gateway.config.ts"; const HOOKS_VITEST_CONFIG = "test/vitest/vitest.hooks.config.ts"; const INFRA_VITEST_CONFIG = "test/vitest/vitest.infra.config.ts"; @@ -103,6 +110,10 @@ const PLUGIN_SDK_LIGHT_VITEST_CONFIG = "test/vitest/vitest.plugin-sdk-light.conf const PLUGIN_SDK_VITEST_CONFIG = "test/vitest/vitest.plugin-sdk.config.ts"; const PLUGINS_VITEST_CONFIG = "test/vitest/vitest.plugins.config.ts"; const UNIT_FAST_VITEST_CONFIG = "test/vitest/vitest.unit-fast.config.ts"; +const UNIT_SECURITY_VITEST_CONFIG = "test/vitest/vitest.unit-security.config.ts"; +const UNIT_SRC_VITEST_CONFIG = "test/vitest/vitest.unit-src.config.ts"; +const UNIT_SUPPORT_VITEST_CONFIG = "test/vitest/vitest.unit-support.config.ts"; +const UNIT_UI_VITEST_CONFIG = "test/vitest/vitest.unit-ui.config.ts"; const PROCESS_VITEST_CONFIG = "test/vitest/vitest.process.config.ts"; const RUNTIME_CONFIG_VITEST_CONFIG = "test/vitest/vitest.runtime-config.config.ts"; const SECRETS_VITEST_CONFIG = "test/vitest/vitest.secrets.config.ts"; @@ -119,6 +130,9 @@ const CHANGED_ARGS_PATTERN = /^--changed(?:=(.+))?$/u; const VITEST_CONFIG_BY_KIND = { acp: ACP_VITEST_CONFIG, agent: AGENTS_VITEST_CONFIG, + autoReplyCore: AUTO_REPLY_CORE_VITEST_CONFIG, + autoReplyReply: AUTO_REPLY_REPLY_VITEST_CONFIG, + autoReplyTopLevel: AUTO_REPLY_TOP_LEVEL_VITEST_CONFIG, autoReply: AUTO_REPLY_VITEST_CONFIG, boundary: BOUNDARY_VITEST_CONFIG, bundled: BUNDLED_VITEST_CONFIG, @@ -161,6 +175,10 @@ const VITEST_CONFIG_BY_KIND = { extensionVoiceCall: EXTENSION_VOICE_CALL_VITEST_CONFIG, extensionWhatsApp: EXTENSION_WHATSAPP_VITEST_CONFIG, extensionZalo: EXTENSION_ZALO_VITEST_CONFIG, + gatewayClient: GATEWAY_CLIENT_VITEST_CONFIG, + gatewayCore: GATEWAY_CORE_VITEST_CONFIG, + gatewayMethods: GATEWAY_METHODS_VITEST_CONFIG, + gatewayServer: GATEWAY_SERVER_VITEST_CONFIG, gateway: GATEWAY_VITEST_CONFIG, hooks: HOOKS_VITEST_CONFIG, infra: INFRA_VITEST_CONFIG, @@ -172,6 +190,10 @@ const VITEST_CONFIG_BY_KIND = { pluginSdkLight: PLUGIN_SDK_LIGHT_VITEST_CONFIG, process: PROCESS_VITEST_CONFIG, unitFast: UNIT_FAST_VITEST_CONFIG, + unitSecurity: UNIT_SECURITY_VITEST_CONFIG, + unitSrc: UNIT_SRC_VITEST_CONFIG, + unitSupport: UNIT_SUPPORT_VITEST_CONFIG, + unitUi: UNIT_UI_VITEST_CONFIG, runtimeConfig: RUNTIME_CONFIG_VITEST_CONFIG, secrets: SECRETS_VITEST_CONFIG, sharedCore: SHARED_CORE_VITEST_CONFIG, @@ -814,6 +836,10 @@ export function buildVitestRunPlans( "contractsPlugin", "bundled", "gateway", + "gatewayCore", + "gatewayClient", + "gatewayMethods", + "gatewayServer", "hooks", "infra", "runtimeConfig", @@ -834,9 +860,16 @@ export function buildVitestRunPlans( "commandLight", "command", "autoReply", + "autoReplyCore", + "autoReplyReply", + "autoReplyTopLevel", "agent", "plugin", "ui", + "unitSrc", + "unitSecurity", + "unitSupport", + "unitUi", "utils", "wizard", "e2e",