diff --git a/packages/memory-host-sdk/src/host/embeddings.test.ts b/packages/memory-host-sdk/src/host/embeddings.test.ts index 2408dcf8b73..016ce7dd421 100644 --- a/packages/memory-host-sdk/src/host/embeddings.test.ts +++ b/packages/memory-host-sdk/src/host/embeddings.test.ts @@ -264,6 +264,8 @@ describe("embedding provider remote overrides", () => { }); it("fails fast when Gemini remote apiKey is an unresolved SecretRef", async () => { + vi.stubEnv("GEMINI_API_KEY", ""); + await expect( createEmbeddingProvider({ config: {} as never, diff --git a/src/infra/vitest-e2e-config.test.ts b/src/infra/vitest-e2e-config.test.ts index 9d8a81b425a..c490e8ba592 100644 --- a/src/infra/vitest-e2e-config.test.ts +++ b/src/infra/vitest-e2e-config.test.ts @@ -1,4 +1,8 @@ import { describe, expect, it } from "vitest"; +import { + normalizeConfigPath, + normalizeConfigPaths, +} from "../../test/helpers/vitest-config-paths.js"; import { BUNDLED_PLUGIN_E2E_TEST_GLOB } from "../../test/vitest/vitest.bundled-plugin-paths.ts"; import e2eConfig from "../../test/vitest/vitest.e2e.config.ts"; @@ -18,7 +22,9 @@ describe("e2e vitest config", () => { ]); expect(e2eConfig.test?.pool).toBe("threads"); expect(e2eConfig.test?.isolate).toBe(false); - expect(e2eConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); - expect(e2eConfig.test?.setupFiles).toContain("test/setup-openclaw-runtime.ts"); + expect(normalizeConfigPath(e2eConfig.test?.runner)).toBe("test/non-isolated-runner.ts"); + expect(normalizeConfigPaths(e2eConfig.test?.setupFiles)).toContain( + "test/setup-openclaw-runtime.ts", + ); }); }); diff --git a/src/infra/vitest-live-config.test.ts b/src/infra/vitest-live-config.test.ts index d7bf0ba746b..f697ebd99ee 100644 --- a/src/infra/vitest-live-config.test.ts +++ b/src/infra/vitest-live-config.test.ts @@ -1,4 +1,8 @@ import { describe, expect, it } from "vitest"; +import { + normalizeConfigPath, + normalizeConfigPaths, +} from "../../test/helpers/vitest-config-paths.js"; import { BUNDLED_PLUGIN_LIVE_TEST_GLOB } from "../../test/vitest/vitest.bundled-plugin-paths.ts"; import liveConfig from "../../test/vitest/vitest.live.config.ts"; @@ -10,7 +14,7 @@ describe("live vitest config", () => { it("keeps live tests on thread workers with the non-isolated runner", () => { expect(liveConfig.test?.pool).toBe("threads"); expect(liveConfig.test?.isolate).toBe(false); - expect(liveConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(liveConfig.test?.runner)).toBe("test/non-isolated-runner.ts"); }); it("includes live test globs and runtime setup", () => { @@ -19,6 +23,8 @@ describe("live vitest config", () => { "test/**/*.live.test.ts", BUNDLED_PLUGIN_LIVE_TEST_GLOB, ]); - expect(liveConfig.test?.setupFiles).toContain("test/setup-openclaw-runtime.ts"); + expect(normalizeConfigPaths(liveConfig.test?.setupFiles)).toContain( + "test/setup-openclaw-runtime.ts", + ); }); }); diff --git a/src/memory-host-sdk/host/embeddings.test.ts b/src/memory-host-sdk/host/embeddings.test.ts index 6d573e28ed1..317a6ff498c 100644 --- a/src/memory-host-sdk/host/embeddings.test.ts +++ b/src/memory-host-sdk/host/embeddings.test.ts @@ -240,6 +240,8 @@ describe("embedding provider remote overrides", () => { }); it("fails fast when Gemini remote apiKey is an unresolved SecretRef", async () => { + vi.stubEnv("GEMINI_API_KEY", ""); + await expect( createEmbeddingProvider({ config: {} as never, diff --git a/test/helpers/vitest-config-paths.ts b/test/helpers/vitest-config-paths.ts new file mode 100644 index 00000000000..1acdcebf91b --- /dev/null +++ b/test/helpers/vitest-config-paths.ts @@ -0,0 +1,20 @@ +import path from "node:path"; + +export function normalizeConfigPath(value: unknown): unknown { + if (typeof value !== "string" || !path.isAbsolute(value)) { + return value; + } + return path.relative(process.cwd(), value).split(path.sep).join("/"); +} + +export function normalizeConfigPaths( + values: readonly unknown[] | string | undefined, +): unknown[] | undefined { + if (values === undefined) { + return undefined; + } + if (!Array.isArray(values)) { + return [normalizeConfigPath(values)]; + } + return values.map((value) => normalizeConfigPath(value)); +} diff --git a/test/vitest-boundary-config.test.ts b/test/vitest-boundary-config.test.ts index 5f4b7ef238a..149bb04ef55 100644 --- a/test/vitest-boundary-config.test.ts +++ b/test/vitest-boundary-config.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import { normalizeConfigPath, normalizeConfigPaths } from "./helpers/vitest-config-paths.js"; import { createBoundaryVitestConfig, loadBoundaryIncludePatternsFromEnv, @@ -16,9 +17,9 @@ describe("boundary vitest config", () => { const config = createBoundaryVitestConfig({}); expect(config.test?.isolate).toBe(false); - expect(config.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(config.test?.runner)).toBe("test/non-isolated-runner.ts"); expect(config.test?.include).toEqual(boundaryTestFiles); - expect(config.test?.setupFiles).toEqual(["test/setup.ts"]); + expect(normalizeConfigPaths(config.test?.setupFiles)).toEqual(["test/setup.ts"]); }); it("narrows boundary includes to matching CLI file filters", () => { diff --git a/test/vitest-projects-config.test.ts b/test/vitest-projects-config.test.ts index 83d7bd4783e..d4907631525 100644 --- a/test/vitest-projects-config.test.ts +++ b/test/vitest-projects-config.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import { normalizeConfigPath, normalizeConfigPaths } from "./helpers/vitest-config-paths.js"; import { createAgentsVitestConfig } from "./vitest/vitest.agents.config.ts"; import bundledConfig from "./vitest/vitest.bundled.config.ts"; import { createCommandsLightVitestConfig } from "./vitest/vitest.commands-light.config.ts"; @@ -29,7 +30,7 @@ describe("projects vitest config", () => { it("keeps the contracts lane on the non-isolated runner by default", () => { const config = createContractsVitestConfig(); expect(config.test.isolate).toBe(false); - expect(config.test.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(config.test.runner)).toBe("test/non-isolated-runner.ts"); }); it("keeps the root ui lane aligned with the isolated jsdom setup", () => { @@ -37,15 +38,16 @@ describe("projects vitest config", () => { expect(config.test.environment).toBe("jsdom"); expect(config.test.isolate).toBe(true); expect(config.test.runner).toBeUndefined(); - expect(config.test.setupFiles).not.toContain("test/setup-openclaw-runtime.ts"); - expect(config.test.setupFiles).toContain("ui/src/test-helpers/lit-warnings.setup.ts"); + const setupFiles = normalizeConfigPaths(config.test.setupFiles); + expect(setupFiles).not.toContain("test/setup-openclaw-runtime.ts"); + expect(setupFiles).toContain("ui/src/test-helpers/lit-warnings.setup.ts"); expect(config.test.deps?.optimizer?.web?.enabled).toBe(true); }); it("keeps the unit lane on the non-isolated runner by default", () => { const config = createUnitVitestConfig(); expect(config.test.isolate).toBe(false); - expect(config.test.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(config.test.runner)).toBe("test/non-isolated-runner.ts"); }); it("keeps the unit-fast lane on shared workers without the reset-heavy runner", () => { @@ -57,6 +59,6 @@ describe("projects vitest config", () => { it("keeps the bundled lane on thread workers with the non-isolated runner", () => { expect(bundledConfig.test?.pool).toBe("threads"); expect(bundledConfig.test?.isolate).toBe(false); - expect(bundledConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(bundledConfig.test?.runner)).toBe("test/non-isolated-runner.ts"); }); }); diff --git a/test/vitest-scoped-config.test.ts b/test/vitest-scoped-config.test.ts index c0b74c0d085..a3bb92877a2 100644 --- a/test/vitest-scoped-config.test.ts +++ b/test/vitest-scoped-config.test.ts @@ -4,6 +4,7 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; import { BUNDLED_PLUGIN_TEST_GLOB, bundledPluginFile } from "./helpers/bundled-plugin-paths.js"; import { cleanupTempDirs, makeTempDir } from "./helpers/temp-dir.js"; +import { normalizeConfigPath, normalizeConfigPaths } from "./helpers/vitest-config-paths.js"; import { createAcpVitestConfig } from "./vitest/vitest.acp.config.ts"; import { createAgentsVitestConfig } from "./vitest/vitest.agents.config.ts"; import { createAutoReplyCoreVitestConfig } from "./vitest/vitest.auto-reply-core.config.ts"; @@ -93,8 +94,11 @@ describe("createScopedVitestConfig", () => { it("applies the non-isolated runner by default", () => { const config = createScopedVitestConfig(["src/example.test.ts"], { env: {} }); expect(config.test?.isolate).toBe(false); - expect(config.test?.runner).toBe("./test/non-isolated-runner.ts"); - expect(config.test?.setupFiles).toEqual(["test/setup.ts", "test/setup-openclaw-runtime.ts"]); + expect(normalizeConfigPath(config.test?.runner)).toBe("test/non-isolated-runner.ts"); + expect(normalizeConfigPaths(config.test?.setupFiles)).toEqual([ + "test/setup.ts", + "test/setup-openclaw-runtime.ts", + ]); }); it("passes through a scoped root dir when provided", () => { @@ -153,7 +157,7 @@ describe("createScopedVitestConfig", () => { setupFiles: ["test/setup.extensions.ts"], }); - expect(config.test?.setupFiles).toEqual([ + expect(normalizeConfigPaths(config.test?.setupFiles)).toEqual([ "test/setup.ts", "test/setup.extensions.ts", "test/setup-openclaw-runtime.ts", @@ -236,13 +240,13 @@ describe("scoped vitest configs", () => { ]) { expect(config.test?.pool).toBe("threads"); expect(config.test?.isolate).toBe(false); - expect(config.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(config.test?.runner)).toBe("test/non-isolated-runner.ts"); } for (const config of [defaultGatewayConfig, defaultCommandsConfig, defaultAgentsConfig]) { expect(config.test?.pool).toBe("threads"); expect(config.test?.isolate).toBe(false); - expect(config.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(config.test?.runner)).toBe("test/non-isolated-runner.ts"); } expect(defaultUiConfig.test?.pool).toBe("threads"); @@ -251,9 +255,9 @@ describe("scoped vitest configs", () => { }); it("keeps the process lane off the openclaw runtime setup", () => { - expect(defaultProcessConfig.test?.setupFiles).toEqual(["test/setup.ts"]); - expect(defaultRuntimeConfig.test?.setupFiles).toEqual(["test/setup.ts"]); - expect(defaultPluginSdkConfig.test?.setupFiles).toEqual([ + expect(normalizeConfigPaths(defaultProcessConfig.test?.setupFiles)).toEqual(["test/setup.ts"]); + expect(normalizeConfigPaths(defaultRuntimeConfig.test?.setupFiles)).toEqual(["test/setup.ts"]); + expect(normalizeConfigPaths(defaultPluginSdkConfig.test?.setupFiles)).toEqual([ "test/setup.ts", "test/setup-openclaw-runtime.ts", ]); @@ -269,14 +273,20 @@ describe("scoped vitest configs", () => { }); it("keeps selected plugin-sdk and commands light lanes off the openclaw runtime setup", () => { - expect(defaultPluginSdkLightConfig.test?.setupFiles).toEqual(["test/setup.ts"]); - expect(defaultCommandsLightConfig.test?.setupFiles).toEqual(["test/setup.ts"]); + expect(normalizeConfigPaths(defaultPluginSdkLightConfig.test?.setupFiles)).toEqual([ + "test/setup.ts", + ]); + expect(normalizeConfigPaths(defaultCommandsLightConfig.test?.setupFiles)).toEqual([ + "test/setup.ts", + ]); }); it("defaults channel tests to threads with the non-isolated runner", () => { expect(defaultChannelsConfig.test?.isolate).toBe(false); expect(defaultChannelsConfig.test?.pool).toBe("threads"); - expect(defaultChannelsConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(defaultChannelsConfig.test?.runner)).toBe( + "test/non-isolated-runner.ts", + ); }); it("keeps the core channel lane limited to non-extension roots", () => { @@ -314,7 +324,9 @@ describe("scoped vitest configs", () => { it("defaults extension tests to threads with the non-isolated runner", () => { expect(defaultExtensionsConfig.test?.isolate).toBe(false); expect(defaultExtensionsConfig.test?.pool).toBe("threads"); - expect(defaultExtensionsConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(defaultExtensionsConfig.test?.runner)).toBe( + "test/non-isolated-runner.ts", + ); }); it("normalizes extension channel include patterns relative to the scoped dir", () => { @@ -434,12 +446,12 @@ describe("scoped vitest configs", () => { expect(defaultChannelsConfig.test?.exclude).not.toContain( bundledPluginFile("telegram", "src/fetch.test.ts"), ); - expect(defaultExtensionsConfig.test?.setupFiles).toEqual([ + expect(normalizeConfigPaths(defaultExtensionsConfig.test?.setupFiles)).toEqual([ "test/setup.ts", "test/setup.extensions.ts", "test/setup-openclaw-runtime.ts", ]); - expect(defaultExtensionTelegramConfig.test?.setupFiles).toEqual([ + expect(normalizeConfigPaths(defaultExtensionTelegramConfig.test?.setupFiles)).toEqual([ "test/setup.ts", "test/setup.extensions.ts", "test/setup-openclaw-runtime.ts", @@ -603,7 +615,9 @@ describe("scoped vitest configs", () => { it("normalizes shared-core include patterns relative to the scoped dir", () => { 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"]); + expect(normalizeConfigPaths(defaultSharedCoreConfig.test?.setupFiles)).toEqual([ + "test/setup.ts", + ]); }); it("normalizes process include patterns relative to the scoped dir", () => { @@ -682,6 +696,6 @@ describe("scoped vitest configs", () => { it("normalizes utils include patterns relative to the scoped dir", () => { 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"]); + expect(normalizeConfigPaths(defaultUtilsConfig.test?.setupFiles)).toEqual(["test/setup.ts"]); }); }); diff --git a/test/vitest-unit-config.test.ts b/test/vitest-unit-config.test.ts index 92ecf470bea..99dba3abec1 100644 --- a/test/vitest-unit-config.test.ts +++ b/test/vitest-unit-config.test.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it } from "vitest"; import { createPatternFileHelper } from "./helpers/pattern-file.js"; +import { normalizeConfigPath, normalizeConfigPaths } from "./helpers/vitest-config-paths.js"; import { createUnitVitestConfig, createUnitVitestConfigWithOptions, @@ -71,7 +72,7 @@ describe("unit vitest config", () => { it("defaults unit tests to the non-isolated runner", () => { const unitConfig = createUnitVitestConfig({}); expect(unitConfig.test?.isolate).toBe(false); - expect(unitConfig.test?.runner).toBe("./test/non-isolated-runner.ts"); + expect(normalizeConfigPath(unitConfig.test?.runner)).toBe("test/non-isolated-runner.ts"); }); it("keeps acp and ui tests out of the generic unit lane", () => { @@ -92,7 +93,7 @@ describe("unit vitest config", () => { it("adds the OpenClaw runtime setup hooks on top of the base setup", () => { const unitConfig = createUnitVitestConfig({}); - expect(unitConfig.test?.setupFiles).toEqual([ + expect(normalizeConfigPaths(unitConfig.test?.setupFiles)).toEqual([ "test/setup.ts", "test/setup-openclaw-runtime.ts", ]);