@@ -19,11 +19,16 @@ const ANSI_CSI_SUFFIX_RE = /^[0-?]*[ -/]*[@-~]/u;
|
19 | 19 | const SUPPRESSED_VITEST_STDERR_PATTERNS = ["[PLUGIN_TIMINGS]"]; |
20 | 20 | export const DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS = 120_000; |
21 | 21 | export const DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS = 60_000; |
| 22 | +export const DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS = 300_000; |
22 | 23 | const VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS"; |
23 | 24 | const VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_HEARTBEAT_MS"; |
24 | 25 | const UI_VITEST_CONFIG = "test/vitest/vitest.ui.config.ts"; |
25 | 26 | const UNIT_UI_VITEST_CONFIG = "test/vitest/vitest.unit-ui.config.ts"; |
26 | 27 | const TOOLING_VITEST_CONFIG = "test/vitest/vitest.tooling.config.ts"; |
| 28 | +const LONG_RUNNING_VITEST_CONFIGS = new Set([ |
| 29 | +"test/vitest/vitest.e2e.config.ts", |
| 30 | +"test/vitest/vitest.ui-e2e.config.ts", |
| 31 | +]); |
27 | 32 | const TOOLING_EXCLUDED_TESTS = new Set([ |
28 | 33 | ...boundaryTestFiles, |
29 | 34 | "test/scripts/openclaw-e2e-instance.test.ts", |
@@ -230,22 +235,57 @@ export function resolveRunVitestSpawnEnv(env = process.env, argv = []) {
|
230 | 235 | if (explicitMode !== "run" && !isTruthyEnvValue(env.CI)) { |
231 | 236 | return env; |
232 | 237 | } |
| 238 | +const defaultTimeoutMs = resolveDefaultVitestNoOutputTimeoutMs(argv); |
233 | 239 | const hasTimeout = Object.hasOwn(env, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY); |
234 | 240 | const timeoutMs = hasTimeout |
235 | 241 | ? parsePositiveInt(env[VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY]) |
236 | | - : DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS; |
| 242 | + : defaultTimeoutMs; |
237 | 243 | const hasHeartbeat = Object.hasOwn(env, VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY); |
238 | 244 | return { |
239 | 245 | ...env, |
240 | 246 | ...(!hasTimeout |
241 | | - ? { [VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY]: String(DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS) } |
| 247 | + ? { [VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY]: String(defaultTimeoutMs) } |
242 | 248 | : {}), |
243 | 249 | ...(!hasHeartbeat && timeoutMs !== null && DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS < timeoutMs |
244 | 250 | ? { [VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY]: String(DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS) } |
245 | 251 | : {}), |
246 | 252 | }; |
247 | 253 | } |
248 | 254 | |
| 255 | +export function resolveDefaultVitestNoOutputTimeoutMs(argv = []) { |
| 256 | +const config = resolveVitestConfigArg(argv); |
| 257 | +if (config !== null && isLongRunningVitestConfig(config)) { |
| 258 | +return DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS; |
| 259 | +} |
| 260 | +return DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS; |
| 261 | +} |
| 262 | + |
| 263 | +function resolveVitestConfigArg(argv) { |
| 264 | +for (let index = 0; index < argv.length; index += 1) { |
| 265 | +const arg = argv[index]; |
| 266 | +if (arg === "--") { |
| 267 | +return null; |
| 268 | +} |
| 269 | +if (arg === "--config" || arg === "-c") { |
| 270 | +return argv[index + 1] ?? null; |
| 271 | +} |
| 272 | +if (arg.startsWith("--config=")) { |
| 273 | +return arg.slice("--config=".length); |
| 274 | +} |
| 275 | +} |
| 276 | +return null; |
| 277 | +} |
| 278 | + |
| 279 | +function isLongRunningVitestConfig(config) { |
| 280 | +const normalized = path.normalize(config).replaceAll(path.sep, "/").replace(/^\.\//u, ""); |
| 281 | +for (const candidate of LONG_RUNNING_VITEST_CONFIGS) { |
| 282 | +if (normalized === candidate || normalized.endsWith(`/${candidate}`)) { |
| 283 | +return true; |
| 284 | +} |
| 285 | +} |
| 286 | +return false; |
| 287 | +} |
| 288 | + |
249 | 289 | export function resolveVitestSpawnParams(env = process.env, platform = process.platform) { |
250 | 290 | return { |
251 | 291 | env: resolveVitestSpawnEnv(env), |
|