diff --git a/packages/memory-host-sdk/src/host/post-json.test.ts b/packages/memory-host-sdk/src/host/post-json.test.ts index d09fa694782..fb8847b8184 100644 --- a/packages/memory-host-sdk/src/host/post-json.test.ts +++ b/packages/memory-host-sdk/src/host/post-json.test.ts @@ -1,30 +1,39 @@ -import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("./remote-http.js", () => ({ withRemoteHttpResponse: vi.fn(), })); -let postJson: typeof import("./post-json.js").postJson; -let withRemoteHttpResponse: typeof import("./remote-http.js").withRemoteHttpResponse; +const { postJson } = await import("./post-json.js"); +const { withRemoteHttpResponse } = await import("./remote-http.js"); +const remoteHttpMock = vi.mocked(withRemoteHttpResponse); + +function jsonResponse(payload: unknown, status = 200): Response { + return { + ok: status >= 200 && status < 300, + status, + json: async () => payload, + text: async () => JSON.stringify(payload), + } as Response; +} + +function textResponse(body: string, status: number): Response { + return { + ok: status >= 200 && status < 300, + status, + json: async () => JSON.parse(body) as unknown, + text: async () => body, + } as Response; +} describe("postJson", () => { - let remoteHttpMock: ReturnType>; - - beforeAll(async () => { - ({ postJson } = await import("./post-json.js")); - ({ withRemoteHttpResponse } = await import("./remote-http.js")); - remoteHttpMock = vi.mocked(withRemoteHttpResponse); - }); - beforeEach(() => { vi.clearAllMocks(); }); it("parses JSON payload on successful response", async () => { remoteHttpMock.mockImplementationOnce(async (params) => { - return await params.onResponse( - new Response(JSON.stringify({ data: [{ embedding: [1, 2] }] }), { status: 200 }), - ); + return await params.onResponse(jsonResponse({ data: [{ embedding: [1, 2] }] })); }); const result = await postJson({ @@ -40,7 +49,7 @@ describe("postJson", () => { it("attaches status to thrown error when requested", async () => { remoteHttpMock.mockImplementationOnce(async (params) => { - return await params.onResponse(new Response("bad gateway", { status: 502 })); + return await params.onResponse(textResponse("bad gateway", 502)); }); await expect( diff --git a/src/browser-lifecycle-cleanup.test.ts b/src/browser-lifecycle-cleanup.test.ts index a56b1d2352b..6993fdb00e1 100644 --- a/src/browser-lifecycle-cleanup.test.ts +++ b/src/browser-lifecycle-cleanup.test.ts @@ -6,14 +6,14 @@ vi.mock("./plugin-sdk/browser-maintenance.js", () => ({ closeTrackedBrowserTabsForSessions, })); +const { cleanupBrowserSessionsForLifecycleEnd } = await import("./browser-lifecycle-cleanup.js"); + describe("cleanupBrowserSessionsForLifecycleEnd", () => { beforeEach(() => { vi.clearAllMocks(); }); it("normalizes session keys before closing browser sessions", async () => { - const { cleanupBrowserSessionsForLifecycleEnd } = - await import("./browser-lifecycle-cleanup.js"); const onWarn = vi.fn(); await expect( @@ -30,8 +30,6 @@ describe("cleanupBrowserSessionsForLifecycleEnd", () => { }); it("swallows browser cleanup failures", async () => { - const { cleanupBrowserSessionsForLifecycleEnd } = - await import("./browser-lifecycle-cleanup.js"); const onError = vi.fn(); const error = new Error("cleanup failed"); closeTrackedBrowserTabsForSessions.mockRejectedValueOnce(error); diff --git a/src/i18n/registry.test.ts b/src/i18n/registry.test.ts index 8f9493bdf43..b13cdf6044d 100644 --- a/src/i18n/registry.test.ts +++ b/src/i18n/registry.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import { fileURLToPath } from "node:url"; -import { beforeAll, describe, expect, it } from "vitest"; +import { describe, expect, it } from "vitest"; type TranslationTree = { readonly [key: string]: string | TranslationTree | undefined; @@ -18,7 +18,17 @@ const describeWhenUiI18nPresent = fs.existsSync(fileURLToPath(registryModuleUrl) ? describe : describe.skip; -let registry: LocaleRegistry; +const registry = + describeWhenUiI18nPresent === describe + ? ((await import("../../ui/src/i18n/lib/registry.ts")) as LocaleRegistry) + : undefined; + +function getRegistry(): LocaleRegistry { + if (registry === undefined) { + throw new Error("expected UI i18n registry to be present"); + } + return registry; +} function getNestedTranslation(map: TranslationTree | null, ...path: string[]): string | undefined { let value: string | TranslationTree | undefined = map ?? undefined; @@ -32,12 +42,10 @@ function getNestedTranslation(map: TranslationTree | null, ...path: string[]): s } describeWhenUiI18nPresent("ui i18n locale registry", () => { - beforeAll(async () => { - registry = (await import("../../ui/src/i18n/lib/registry.ts")) as LocaleRegistry; - }); - it("lists supported locales", () => { - expect(registry.SUPPORTED_LOCALES).toEqual([ + const localeRegistry = getRegistry(); + + expect(localeRegistry.SUPPORTED_LOCALES).toEqual([ "en", "zh-CN", "zh-TW", @@ -53,34 +61,37 @@ describeWhenUiI18nPresent("ui i18n locale registry", () => { "pl", "th", ]); - expect(registry.DEFAULT_LOCALE).toBe("en"); + expect(localeRegistry.DEFAULT_LOCALE).toBe("en"); }); it("resolves browser locale fallbacks", () => { - expect(registry.resolveNavigatorLocale("de-DE")).toBe("de"); - expect(registry.resolveNavigatorLocale("es-ES")).toBe("es"); - expect(registry.resolveNavigatorLocale("es-MX")).toBe("es"); - expect(registry.resolveNavigatorLocale("pt-PT")).toBe("pt-BR"); - expect(registry.resolveNavigatorLocale("zh-HK")).toBe("zh-TW"); - expect(registry.resolveNavigatorLocale("en-US")).toBe("en"); - expect(registry.resolveNavigatorLocale("ja-JP")).toBe("ja-JP"); - expect(registry.resolveNavigatorLocale("ko-KR")).toBe("ko"); - expect(registry.resolveNavigatorLocale("fr-CA")).toBe("fr"); - expect(registry.resolveNavigatorLocale("tr-TR")).toBe("tr"); - expect(registry.resolveNavigatorLocale("uk-UA")).toBe("uk"); - expect(registry.resolveNavigatorLocale("id-ID")).toBe("id"); - expect(registry.resolveNavigatorLocale("pl-PL")).toBe("pl"); - expect(registry.resolveNavigatorLocale("th-TH")).toBe("th"); + const localeRegistry = getRegistry(); + + expect(localeRegistry.resolveNavigatorLocale("de-DE")).toBe("de"); + expect(localeRegistry.resolveNavigatorLocale("es-ES")).toBe("es"); + expect(localeRegistry.resolveNavigatorLocale("es-MX")).toBe("es"); + expect(localeRegistry.resolveNavigatorLocale("pt-PT")).toBe("pt-BR"); + expect(localeRegistry.resolveNavigatorLocale("zh-HK")).toBe("zh-TW"); + expect(localeRegistry.resolveNavigatorLocale("en-US")).toBe("en"); + expect(localeRegistry.resolveNavigatorLocale("ja-JP")).toBe("ja-JP"); + expect(localeRegistry.resolveNavigatorLocale("ko-KR")).toBe("ko"); + expect(localeRegistry.resolveNavigatorLocale("fr-CA")).toBe("fr"); + expect(localeRegistry.resolveNavigatorLocale("tr-TR")).toBe("tr"); + expect(localeRegistry.resolveNavigatorLocale("uk-UA")).toBe("uk"); + expect(localeRegistry.resolveNavigatorLocale("id-ID")).toBe("id"); + expect(localeRegistry.resolveNavigatorLocale("pl-PL")).toBe("pl"); + expect(localeRegistry.resolveNavigatorLocale("th-TH")).toBe("th"); }); it("loads lazy locale translations from the registry", async () => { + const localeRegistry = getRegistry(); const [de, es, ptBR, zhCN, th, en] = await Promise.all([ - registry.loadLazyLocaleTranslation("de"), - registry.loadLazyLocaleTranslation("es"), - registry.loadLazyLocaleTranslation("pt-BR"), - registry.loadLazyLocaleTranslation("zh-CN"), - registry.loadLazyLocaleTranslation("th"), - registry.loadLazyLocaleTranslation("en"), + localeRegistry.loadLazyLocaleTranslation("de"), + localeRegistry.loadLazyLocaleTranslation("es"), + localeRegistry.loadLazyLocaleTranslation("pt-BR"), + localeRegistry.loadLazyLocaleTranslation("zh-CN"), + localeRegistry.loadLazyLocaleTranslation("th"), + localeRegistry.loadLazyLocaleTranslation("en"), ]); expect(getNestedTranslation(de, "common", "health")).toBe("Status"); diff --git a/src/install-sh-version.test.ts b/src/install-sh-version.test.ts index 5c5ff45d1fc..9c6b6e57692 100644 --- a/src/install-sh-version.test.ts +++ b/src/install-sh-version.test.ts @@ -5,16 +5,18 @@ import { afterEach, describe, expect, it } from "vitest"; import { cleanupTempDirs, makeTempDir } from "../test/helpers/temp-dir.js"; const tempRoots: string[] = []; +const installerPath = path.join(process.cwd(), "scripts", "install.sh"); +const installerSource = fs.readFileSync(installerPath, "utf-8"); +const versionHelperStart = installerSource.indexOf("load_install_version_helpers() {"); +const versionHelperEnd = installerSource.indexOf("\nis_gateway_daemon_loaded() {"); + +if (versionHelperStart < 0 || versionHelperEnd < 0) { + throw new Error("install.sh version helper block not found"); +} + +const versionHelperSource = installerSource.slice(versionHelperStart, versionHelperEnd); function resolveInstallerVersionCases(params: { stdinCwd: string }): string[] { - const installerPath = path.join(process.cwd(), "scripts", "install.sh"); - const installerSource = fs.readFileSync(installerPath, "utf-8"); - const versionHelperStart = installerSource.indexOf("load_install_version_helpers() {"); - const versionHelperEnd = installerSource.indexOf("\nis_gateway_daemon_loaded() {"); - if (versionHelperStart < 0 || versionHelperEnd < 0) { - throw new Error("install.sh version helper block not found"); - } - const versionHelperSource = installerSource.slice(versionHelperStart, versionHelperEnd); const output = execFileSync( "bash", [ diff --git a/src/memory-host-sdk/host/internal.test.ts b/src/memory-host-sdk/host/internal.test.ts index 1063f9b7be3..8e0e3d7773e 100644 --- a/src/memory-host-sdk/host/internal.test.ts +++ b/src/memory-host-sdk/host/internal.test.ts @@ -2,7 +2,7 @@ import fsSync from "node:fs"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("../../media/mime.js", () => ({ detectMime: async (opts: { filePath?: string }) => { @@ -30,17 +30,11 @@ import { type MemoryMultimodalSettings, } from "./multimodal.js"; -let sharedTempRoot = ""; +const sharedTempRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "memory-host-sdk-tests-")); let sharedTempId = 0; -beforeAll(() => { - sharedTempRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "memory-host-sdk-tests-")); -}); - afterAll(() => { - if (sharedTempRoot) { - fsSync.rmSync(sharedTempRoot, { recursive: true, force: true }); - } + fsSync.rmSync(sharedTempRoot, { recursive: true, force: true }); }); function setupTempDirLifecycle(prefix: string): () => string { diff --git a/src/memory-host-sdk/host/post-json.test.ts b/src/memory-host-sdk/host/post-json.test.ts index d09fa694782..fb8847b8184 100644 --- a/src/memory-host-sdk/host/post-json.test.ts +++ b/src/memory-host-sdk/host/post-json.test.ts @@ -1,30 +1,39 @@ -import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("./remote-http.js", () => ({ withRemoteHttpResponse: vi.fn(), })); -let postJson: typeof import("./post-json.js").postJson; -let withRemoteHttpResponse: typeof import("./remote-http.js").withRemoteHttpResponse; +const { postJson } = await import("./post-json.js"); +const { withRemoteHttpResponse } = await import("./remote-http.js"); +const remoteHttpMock = vi.mocked(withRemoteHttpResponse); + +function jsonResponse(payload: unknown, status = 200): Response { + return { + ok: status >= 200 && status < 300, + status, + json: async () => payload, + text: async () => JSON.stringify(payload), + } as Response; +} + +function textResponse(body: string, status: number): Response { + return { + ok: status >= 200 && status < 300, + status, + json: async () => JSON.parse(body) as unknown, + text: async () => body, + } as Response; +} describe("postJson", () => { - let remoteHttpMock: ReturnType>; - - beforeAll(async () => { - ({ postJson } = await import("./post-json.js")); - ({ withRemoteHttpResponse } = await import("./remote-http.js")); - remoteHttpMock = vi.mocked(withRemoteHttpResponse); - }); - beforeEach(() => { vi.clearAllMocks(); }); it("parses JSON payload on successful response", async () => { remoteHttpMock.mockImplementationOnce(async (params) => { - return await params.onResponse( - new Response(JSON.stringify({ data: [{ embedding: [1, 2] }] }), { status: 200 }), - ); + return await params.onResponse(jsonResponse({ data: [{ embedding: [1, 2] }] })); }); const result = await postJson({ @@ -40,7 +49,7 @@ describe("postJson", () => { it("attaches status to thrown error when requested", async () => { remoteHttpMock.mockImplementationOnce(async (params) => { - return await params.onResponse(new Response("bad gateway", { status: 502 })); + return await params.onResponse(textResponse("bad gateway", 502)); }); await expect( diff --git a/src/pairing/setup-code.test.ts b/src/pairing/setup-code.test.ts index 2e13f01247a..13cbb7a86d4 100644 --- a/src/pairing/setup-code.test.ts +++ b/src/pairing/setup-code.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { SecretInput } from "../config/types.secrets.js"; vi.mock("../infra/device-bootstrap.js", () => ({ @@ -8,9 +8,9 @@ vi.mock("../infra/device-bootstrap.js", () => ({ })), })); -let encodePairingSetupCode: typeof import("./setup-code.js").encodePairingSetupCode; -let resolvePairingSetupFromConfig: typeof import("./setup-code.js").resolvePairingSetupFromConfig; -let issueDeviceBootstrapTokenMock: typeof import("../infra/device-bootstrap.js").issueDeviceBootstrapToken; +const { encodePairingSetupCode, resolvePairingSetupFromConfig } = await import("./setup-code.js"); +const { issueDeviceBootstrapToken: issueDeviceBootstrapTokenMock } = + await import("../infra/device-bootstrap.js"); describe("pairing setup code", () => { type ResolvedSetup = Awaited>; @@ -185,12 +185,6 @@ describe("pairing setup code", () => { vi.stubEnv("OPENCLAW_GATEWAY_PORT", ""); }); - beforeAll(async () => { - ({ encodePairingSetupCode, resolvePairingSetupFromConfig } = await import("./setup-code.js")); - ({ issueDeviceBootstrapToken: issueDeviceBootstrapTokenMock } = - await import("../infra/device-bootstrap.js")); - }); - beforeEach(() => { vi.mocked(issueDeviceBootstrapTokenMock).mockClear(); }); diff --git a/src/security/skill-scanner.test.ts b/src/security/skill-scanner.test.ts index b8b5a87b210..39994ae5aee 100644 --- a/src/security/skill-scanner.test.ts +++ b/src/security/skill-scanner.test.ts @@ -2,7 +2,7 @@ import fsSync from "node:fs"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { clearSkillScanCacheForTest, isScannable, @@ -16,17 +16,11 @@ import type { SkillScanOptions } from "./skill-scanner.js"; // Helpers // --------------------------------------------------------------------------- -let fixtureRoot = ""; +const fixtureRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "skill-scanner-test-")); let fixtureId = 0; -beforeAll(() => { - fixtureRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "skill-scanner-test-")); -}); - afterAll(() => { - if (fixtureRoot) { - fsSync.rmSync(fixtureRoot, { recursive: true, force: true }); - } + fsSync.rmSync(fixtureRoot, { recursive: true, force: true }); }); function makeTmpDir(): string { diff --git a/src/trajectory/export.test.ts b/src/trajectory/export.test.ts index f709e0e0a46..f268e3f9eab 100644 --- a/src/trajectory/export.test.ts +++ b/src/trajectory/export.test.ts @@ -2,12 +2,12 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import type { Message, Usage } from "@mariozechner/pi-ai"; -import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { afterAll, describe, expect, it } from "vitest"; import { exportTrajectoryBundle, resolveDefaultTrajectoryExportDir } from "./export.js"; import { resolveTrajectoryPointerFilePath } from "./paths.js"; import type { TrajectoryEvent } from "./types.js"; -let tempRoot = ""; +const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-trajectory-")); let tempDirId = 0; function makeTempDir(): string { @@ -180,14 +180,8 @@ function writeToolCallSessionFile(sessionFile: string): void { ); } -beforeAll(() => { - tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-trajectory-")); -}); - afterAll(() => { - if (tempRoot) { - fs.rmSync(tempRoot, { recursive: true, force: true }); - } + fs.rmSync(tempRoot, { recursive: true, force: true }); }); describe("exportTrajectoryBundle", () => { diff --git a/src/tts/tts.test.ts b/src/tts/tts.test.ts index 891a3626378..e613f018222 100644 --- a/src/tts/tts.test.ts +++ b/src/tts/tts.test.ts @@ -1,4 +1,4 @@ -import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; const loadBundledPluginPublicSurfaceModuleSync = vi.hoisted(() => vi.fn()); const loadActivatedBundledPluginPublicSurfaceModuleSync = vi.hoisted(() => vi.fn()); @@ -31,13 +31,9 @@ vi.mock("../plugin-sdk/facade-runtime.js", () => ({ loadBundledPluginPublicSurfaceModuleSync, })); +const tts = await import("./tts.js"); + describe("tts runtime facade", () => { - let tts: typeof import("./tts.js"); - - beforeAll(async () => { - tts = await import("./tts.js"); - }); - beforeEach(() => { loadActivatedBundledPluginPublicSurfaceModuleSync.mockReset(); loadBundledPluginPublicSurfaceModuleSync.mockReset();