test: restore moved Vitest config discovery

This commit is contained in:
Peter Steinberger
2026-04-10 14:20:11 +01:00
parent d2b9d918af
commit 1b1853f0cc
7 changed files with 114 additions and 52 deletions

View File

@@ -218,6 +218,9 @@ async function main() {
`[test] running ${parallelSpecs.length} Vitest shards with parallelism ${concurrency}`,
);
const parallelExitCode = await runVitestSpecsParallel(parallelSpecs, concurrency);
console.error(
`[test] completed ${parallelSpecs.length} Vitest shards; Vitest summaries above are per-shard, not aggregate totals.`,
);
releaseLockOnce();
if (parallelExitCode !== 0) {
process.exit(parallelExitCode);

View File

@@ -114,7 +114,7 @@ describe("docker build cache layout", () => {
/^COPY(?:\s+--chown=\S+)?\s+scripts\/postinstall-bundled-plugins\.mjs scripts\/npm-runner\.mjs scripts\/windows-cmd-helpers\.mjs \.\/scripts\/$/m,
);
expectPatternAfterInstall(
/^COPY(?:\s+--chown=\S+)?\s+tsconfig\.json tsconfig\.plugin-sdk\.dts\.json tsdown\.config\.ts vitest\.config\.ts vitest\.e2e\.config\.ts vitest\.performance-config\.ts vitest\.shared\.config\.ts vitest\.system-load\.ts vitest\.bundled-plugin-paths\.ts openclaw\.mjs \.\/$/m,
/^COPY(?:\s+--chown=\S+)?\s+tsconfig\.json tsconfig\.plugin-sdk\.dts\.json tsdown\.config\.ts vitest\.config\.ts openclaw\.mjs \.\/$/m,
);
expectPatternAfterInstall(/^COPY(?:\s+--chown=\S+)?\s+src \.\/src$/m);
expectPatternAfterInstall(/^COPY(?:\s+--chown=\S+)?\s+test \.\/test$/m);

View File

@@ -79,6 +79,14 @@ describe("resolveVitestIsolation", () => {
expect(resolveVitestIsolation({ OPENCLAW_TEST_NO_ISOLATE: "0" })).toBe(false);
expect(resolveVitestIsolation({ OPENCLAW_TEST_NO_ISOLATE: "false" })).toBe(false);
});
it("resolves scoped discovery dirs from the repo root after config relocation", () => {
const config = createExtensionMatrixVitestConfig({});
expect(config.root).toBe(process.cwd());
expect(config.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(config.test?.include).toContain("matrix/**/*.test.ts");
});
});
describe("createScopedVitestConfig", () => {
@@ -94,7 +102,7 @@ describe("createScopedVitestConfig", () => {
dir: "src",
env: {},
});
expect(config.test?.dir).toBe("src");
expect(config.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(config.test?.include).toEqual(["example.test.ts"]);
});
@@ -310,7 +318,7 @@ describe("scoped vitest configs", () => {
});
it("normalizes extension channel include patterns relative to the scoped dir", () => {
expect(defaultExtensionChannelsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionChannelsConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionChannelsConfig.test?.include).toEqual(
expect.arrayContaining([
"discord/**/*.test.ts",
@@ -323,88 +331,90 @@ describe("scoped vitest configs", () => {
});
it("normalizes bluebubbles extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionBlueBubblesConfig.test?.dir).toBe("extensions");
expect(defaultExtensionBlueBubblesConfig.test?.dir).toBe(
path.join(process.cwd(), "extensions"),
);
expect(defaultExtensionBlueBubblesConfig.test?.include).toEqual(["bluebubbles/**/*.test.ts"]);
});
it("normalizes acpx extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionAcpxConfig.test?.dir).toBe("extensions");
expect(defaultExtensionAcpxConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionAcpxConfig.test?.include).toEqual(["acpx/**/*.test.ts"]);
});
it("normalizes diffs extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionDiffsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionDiffsConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionDiffsConfig.test?.include).toEqual(["diffs/**/*.test.ts"]);
});
it("normalizes feishu extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionFeishuConfig.test?.dir).toBe("extensions");
expect(defaultExtensionFeishuConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionFeishuConfig.test?.include).toEqual(["feishu/**/*.test.ts"]);
});
it("normalizes irc extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionIrcConfig.test?.dir).toBe("extensions");
expect(defaultExtensionIrcConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionIrcConfig.test?.include).toEqual(["irc/**/*.test.ts"]);
});
it("normalizes extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionsConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes extension provider include patterns relative to the scoped dir", () => {
expect(defaultExtensionProvidersConfig.test?.dir).toBe("extensions");
expect(defaultExtensionProvidersConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionProvidersConfig.test?.include).toEqual(
expect.arrayContaining(["openai/**/*.test.ts", "xai/**/*.test.ts", "google/**/*.test.ts"]),
);
});
it("normalizes extension messaging include patterns relative to the scoped dir", () => {
expect(defaultExtensionMessagingConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMessagingConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionMessagingConfig.test?.include).toEqual(
expect.arrayContaining(["googlechat/**/*.test.ts"]),
);
});
it("normalizes matrix extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMatrixConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMatrixConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionMatrixConfig.test?.include).toEqual(["matrix/**/*.test.ts"]);
});
it("normalizes mattermost extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMattermostConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMattermostConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionMattermostConfig.test?.include).toEqual(["mattermost/**/*.test.ts"]);
});
it("normalizes msteams extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMsTeamsConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMsTeamsConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionMsTeamsConfig.test?.include).toEqual(["msteams/**/*.test.ts"]);
});
it("normalizes telegram extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionTelegramConfig.test?.dir).toBe("extensions");
expect(defaultExtensionTelegramConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionTelegramConfig.test?.include).toEqual(["telegram/**/*.test.ts"]);
});
it("normalizes whatsapp extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionWhatsAppConfig.test?.dir).toBe("extensions");
expect(defaultExtensionWhatsAppConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionWhatsAppConfig.test?.include).toEqual(["whatsapp/**/*.test.ts"]);
});
it("normalizes zalo extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionZaloConfig.test?.dir).toBe("extensions");
expect(defaultExtensionZaloConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionZaloConfig.test?.include).toEqual(
expect.arrayContaining(["zalo/**/*.test.ts", "zalouser/**/*.test.ts"]),
);
});
it("normalizes voice-call extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionVoiceCallConfig.test?.dir).toBe("extensions");
expect(defaultExtensionVoiceCallConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionVoiceCallConfig.test?.include).toEqual(["voice-call/**/*.test.ts"]);
});
it("normalizes memory extension include patterns relative to the scoped dir", () => {
expect(defaultExtensionMemoryConfig.test?.dir).toBe("extensions");
expect(defaultExtensionMemoryConfig.test?.dir).toBe(path.join(process.cwd(), "extensions"));
expect(defaultExtensionMemoryConfig.test?.include).toEqual(
expect.arrayContaining(["memory-core/**/*.test.ts", "memory-lancedb/**/*.test.ts"]),
);
@@ -490,12 +500,12 @@ describe("scoped vitest configs", () => {
});
it("normalizes secrets include patterns relative to the scoped dir", () => {
expect(defaultSecretsConfig.test?.dir).toBe("src/secrets");
expect(defaultSecretsConfig.test?.dir).toBe(path.join(process.cwd(), "src", "secrets"));
expect(defaultSecretsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes hooks include patterns relative to the scoped dir", () => {
expect(defaultHooksConfig.test?.dir).toBe("src/hooks");
expect(defaultHooksConfig.test?.dir).toBe(path.join(process.cwd(), "src", "hooks"));
expect(defaultHooksConfig.test?.include).toEqual(["**/*.test.ts"]);
});
@@ -546,7 +556,7 @@ describe("scoped vitest configs", () => {
});
it("normalizes gateway include patterns relative to the scoped dir", () => {
expect(defaultGatewayConfig.test?.dir).toBe("src/gateway");
expect(defaultGatewayConfig.test?.dir).toBe(path.join(process.cwd(), "src", "gateway"));
expect(defaultGatewayConfig.test?.include).toEqual(["**/*.test.ts"]);
expect(defaultGatewayConfig.test?.exclude).toContain("gateway.test.ts");
expect(defaultGatewayConfig.test?.exclude).toContain(
@@ -556,68 +566,68 @@ describe("scoped vitest configs", () => {
});
it("normalizes infra include patterns relative to the scoped dir", () => {
expect(defaultInfraConfig.test?.dir).toBe("src");
expect(defaultInfraConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultInfraConfig.test?.include).toEqual(["infra/**/*.test.ts"]);
});
it("normalizes runtime config include patterns relative to the scoped dir", () => {
expect(defaultRuntimeConfig.test?.dir).toBe("src");
expect(defaultRuntimeConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultRuntimeConfig.test?.include).toEqual(["config/**/*.test.ts"]);
});
it("normalizes cron include patterns relative to the scoped dir", () => {
expect(defaultCronConfig.test?.dir).toBe("src");
expect(defaultCronConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultCronConfig.test?.include).toEqual(["cron/**/*.test.ts"]);
});
it("normalizes daemon include patterns relative to the scoped dir", () => {
expect(defaultDaemonConfig.test?.dir).toBe("src");
expect(defaultDaemonConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultDaemonConfig.test?.include).toEqual(["daemon/**/*.test.ts"]);
});
it("normalizes media include patterns relative to the scoped dir", () => {
expect(defaultMediaConfig.test?.dir).toBe("src");
expect(defaultMediaConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultMediaConfig.test?.include).toEqual(["media/**/*.test.ts"]);
});
it("normalizes logging include patterns relative to the scoped dir", () => {
expect(defaultLoggingConfig.test?.dir).toBe("src");
expect(defaultLoggingConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultLoggingConfig.test?.include).toEqual(["logging/**/*.test.ts"]);
});
it("normalizes plugin-sdk include patterns relative to the scoped dir", () => {
expect(defaultPluginSdkConfig.test?.dir).toBe("src");
expect(defaultPluginSdkConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultPluginSdkConfig.test?.include).toEqual(["plugin-sdk/**/*.test.ts"]);
});
it("normalizes shared-core include patterns relative to the scoped dir", () => {
expect(defaultSharedCoreConfig.test?.dir).toBe("src");
expect(defaultSharedCoreConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultSharedCoreConfig.test?.include).toEqual(["shared/**/*.test.ts"]);
expect(defaultSharedCoreConfig.test?.setupFiles).toEqual(["test/setup.ts"]);
});
it("normalizes process include patterns relative to the scoped dir", () => {
expect(defaultProcessConfig.test?.dir).toBe("src");
expect(defaultProcessConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultProcessConfig.test?.include).toEqual(["process/**/*.test.ts"]);
});
it("normalizes tasks include patterns relative to the scoped dir", () => {
expect(defaultTasksConfig.test?.dir).toBe("src");
expect(defaultTasksConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultTasksConfig.test?.include).toEqual(["tasks/**/*.test.ts"]);
});
it("normalizes wizard include patterns relative to the scoped dir", () => {
expect(defaultWizardConfig.test?.dir).toBe("src");
expect(defaultWizardConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultWizardConfig.test?.include).toEqual(["wizard/**/*.test.ts"]);
});
it("normalizes tui include patterns relative to the scoped dir", () => {
expect(defaultTuiConfig.test?.dir).toBe("src");
expect(defaultTuiConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultTuiConfig.test?.include).toEqual(["tui/**/*.test.ts"]);
});
it("normalizes media-understanding include patterns relative to the scoped dir", () => {
expect(defaultMediaUnderstandingConfig.test?.dir).toBe("src");
expect(defaultMediaUnderstandingConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultMediaUnderstandingConfig.test?.include).toEqual([
"media-understanding/**/*.test.ts",
]);
@@ -634,43 +644,43 @@ describe("scoped vitest configs", () => {
});
it("normalizes acp include patterns relative to the scoped dir", () => {
expect(defaultAcpConfig.test?.dir).toBe("src/acp");
expect(defaultAcpConfig.test?.dir).toBe(path.join(process.cwd(), "src", "acp"));
expect(defaultAcpConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes cli include patterns relative to the scoped dir", () => {
expect(defaultCliConfig.test?.dir).toBe("src/cli");
expect(defaultCliConfig.test?.dir).toBe(path.join(process.cwd(), "src", "cli"));
expect(defaultCliConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes commands include patterns relative to the scoped dir", () => {
expect(defaultCommandsConfig.test?.dir).toBe("src/commands");
expect(defaultCommandsConfig.test?.dir).toBe(path.join(process.cwd(), "src", "commands"));
expect(defaultCommandsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes auto-reply include patterns relative to the scoped dir", () => {
expect(defaultAutoReplyConfig.test?.dir).toBe("src/auto-reply");
expect(defaultAutoReplyConfig.test?.dir).toBe(path.join(process.cwd(), "src", "auto-reply"));
expect(defaultAutoReplyConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes agents include patterns relative to the scoped dir", () => {
expect(defaultAgentsConfig.test?.dir).toBe("src/agents");
expect(defaultAgentsConfig.test?.dir).toBe(path.join(process.cwd(), "src", "agents"));
expect(defaultAgentsConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes plugins include patterns relative to the scoped dir", () => {
expect(defaultPluginsConfig.test?.dir).toBe("src/plugins");
expect(defaultPluginsConfig.test?.dir).toBe(path.join(process.cwd(), "src", "plugins"));
expect(defaultPluginsConfig.test?.include).toEqual(["**/*.test.ts"]);
expect(defaultPluginsConfig.test?.exclude).toContain("contracts/**");
});
it("normalizes ui include patterns relative to the scoped dir", () => {
expect(defaultUiConfig.test?.dir).toBe("ui/src/ui");
expect(defaultUiConfig.test?.dir).toBe(path.join(process.cwd(), "ui", "src", "ui"));
expect(defaultUiConfig.test?.include).toEqual(["**/*.test.ts"]);
});
it("normalizes utils include patterns relative to the scoped dir", () => {
expect(defaultUtilsConfig.test?.dir).toBe("src");
expect(defaultUtilsConfig.test?.dir).toBe(path.join(process.cwd(), "src"));
expect(defaultUtilsConfig.test?.include).toEqual(["utils/**/*.test.ts"]);
expect(defaultUtilsConfig.test?.setupFiles).toEqual(["test/setup.ts"]);
});

View File

@@ -23,6 +23,18 @@ describe("unit-fast vitest lane", () => {
expect(config.test?.include).toContain("src/commands/status-overview-values.test.ts");
});
it("does not treat moved config paths as CLI include filters", () => {
const config = createUnitFastVitestConfig(
{},
{
argv: ["node", "vitest", "run", "--config", "test/vitest/vitest.unit-fast.config.ts"],
},
);
expect(config.test?.include).toContain("src/plugin-sdk/provider-entry.test.ts");
expect(config.test?.include).toContain("src/commands/status-overview-values.test.ts");
});
it("keeps obvious stateful files out of the unit-fast lane", () => {
expect(isUnitFastTestFile("src/plugin-sdk/temp-path.test.ts")).toBe(false);
expect(resolveUnitFastTestIncludePattern("src/plugin-sdk/temp-path.ts")).toBeNull();

View File

@@ -46,12 +46,45 @@ export function loadPatternListFromEnv(
}
export function loadPatternListFromArgv(argv: string[] = process.argv): string[] | null {
const patterns = argv
.slice(2)
.filter((value) => value !== "run" && value !== "watch" && value !== "bench")
.filter((value) => !value.startsWith("-"))
.filter(looksLikeCliIncludePattern)
.map(normalizeCliPattern);
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;
}

View File

@@ -1,6 +1,7 @@
import path from "node:path";
import { defineConfig } from "vitest/config";
import { loadPatternListFromEnv, narrowIncludePatternsForCli } from "./vitest.pattern-file.ts";
import { sharedVitestConfig } from "./vitest.shared.config.ts";
import { repoRoot, sharedVitestConfig } from "./vitest.shared.config.ts";
import { unitFastTestFiles } from "./vitest.unit-fast-paths.mjs";
function normalizePathPattern(value: string): string {
@@ -144,6 +145,7 @@ export function createScopedVitestConfig(
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);
@@ -173,7 +175,7 @@ export function createScopedVitestConfig(
isolate,
...(runner ? { runner } : { runner: undefined }),
setupFiles,
...(scopedDir ? { dir: scopedDir } : {}),
...(resolvedScopedDir ? { dir: resolvedScopedDir } : {}),
include: relativizeScopedPatterns(includeFromEnv ?? cliInclude ?? include, scopedDir),
exclude,
...(options?.pool ? { pool: options.pool } : {}),

View File

@@ -159,7 +159,7 @@ export function resolveDefaultVitestPool(
return "threads";
}
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
export const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
const isWindows = process.platform === "win32";
const defaultPool = resolveDefaultVitestPool();
@@ -179,6 +179,7 @@ if (!isCI && localScheduling.throttledBySystem && shouldPrintVitestThrottle(proc
}
export const sharedVitestConfig = {
root: repoRoot,
resolve: {
alias: [
{
@@ -200,6 +201,7 @@ export const sharedVitestConfig = {
],
},
test: {
dir: repoRoot,
testTimeout: 120_000,
hookTimeout: isWindows ? 180_000 : 120_000,
unstubEnvs: true,