diff --git a/src/docker-setup.test.ts b/src/docker-setup.test.ts index e7d9def69..4f77f2611 100644 --- a/src/docker-setup.test.ts +++ b/src/docker-setup.test.ts @@ -1,9 +1,9 @@ import { spawnSync } from "node:child_process"; -import { chmod, copyFile, mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises"; +import { chmod, copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -import { describe, expect, it } from "vitest"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; const repoRoot = resolve(fileURLToPath(new URL(".", import.meta.url)), ".."); @@ -85,8 +85,24 @@ function resolveBashForCompatCheck(): string | null { } describe("docker-setup.sh", () => { + let sandbox: DockerSetupSandbox | null = null; + + beforeAll(async () => { + sandbox = await createDockerSetupSandbox(); + }); + + afterAll(async () => { + if (!sandbox) { + return; + } + await rm(sandbox.rootDir, { recursive: true, force: true }); + sandbox = null; + }); + it("handles env defaults, home-volume mounts, and apt build args", async () => { - const sandbox = await createDockerSetupSandbox(); + if (!sandbox) { + throw new Error("sandbox missing"); + } const result = spawnSync("bash", [sandbox.scriptPath], { cwd: sandbox.rootDir, diff --git a/src/infra/update-startup.test.ts b/src/infra/update-startup.test.ts index 1d0aafd26..45f54a08b 100644 --- a/src/infra/update-startup.test.ts +++ b/src/infra/update-startup.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { UpdateCheckResult } from "./update-check.js"; vi.mock("./openclaw-root.js", () => ({ @@ -24,15 +24,36 @@ vi.mock("../version.js", () => ({ describe("update-startup", () => { const originalEnv = { ...process.env }; + let suiteRoot = ""; + let suiteCase = 0; let tempDir: string; + let resolveOpenClawPackageRoot: (typeof import("./openclaw-root.js"))["resolveOpenClawPackageRoot"]; + let checkUpdateStatus: (typeof import("./update-check.js"))["checkUpdateStatus"]; + let resolveNpmChannelTag: (typeof import("./update-check.js"))["resolveNpmChannelTag"]; + let runGatewayUpdateCheck: (typeof import("./update-startup.js"))["runGatewayUpdateCheck"]; + let loaded = false; + + beforeAll(async () => { + suiteRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-check-suite-")); + }); + beforeEach(async () => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-01-17T10:00:00Z")); - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-check-")); + tempDir = path.join(suiteRoot, `case-${++suiteCase}`); + await fs.mkdir(tempDir, { recursive: true }); process.env.OPENCLAW_STATE_DIR = tempDir; delete process.env.VITEST; process.env.NODE_ENV = "test"; + + // Perf: load mocked modules once (after timers/env are set up). + if (!loaded) { + ({ resolveOpenClawPackageRoot } = await import("./openclaw-root.js")); + ({ checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js")); + ({ runGatewayUpdateCheck } = await import("./update-startup.js")); + loaded = true; + } }); afterEach(async () => { @@ -41,11 +62,15 @@ describe("update-startup", () => { await fs.rm(tempDir, { recursive: true, force: true }); }); - it("logs update hint for npm installs when newer tag exists", async () => { - const { resolveOpenClawPackageRoot } = await import("./openclaw-root.js"); - const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js"); - const { runGatewayUpdateCheck } = await import("./update-startup.js"); + afterAll(async () => { + if (suiteRoot) { + await fs.rm(suiteRoot, { recursive: true, force: true }); + } + suiteRoot = ""; + suiteCase = 0; + }); + it("logs update hint for npm installs when newer tag exists", async () => { vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw"); vi.mocked(checkUpdateStatus).mockResolvedValue({ root: "/opt/openclaw", @@ -76,10 +101,6 @@ describe("update-startup", () => { }); it("uses latest when beta tag is older than release", async () => { - const { resolveOpenClawPackageRoot } = await import("./openclaw-root.js"); - const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js"); - const { runGatewayUpdateCheck } = await import("./update-startup.js"); - vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw"); vi.mocked(checkUpdateStatus).mockResolvedValue({ root: "/opt/openclaw", @@ -110,7 +131,6 @@ describe("update-startup", () => { }); it("skips update check when disabled in config", async () => { - const { runGatewayUpdateCheck } = await import("./update-startup.js"); const log = { info: vi.fn() }; await runGatewayUpdateCheck({