diff --git a/src/infra/update-runner.test.ts b/src/infra/update-runner.test.ts index c56a9d78e..b0678e436 100644 --- a/src/infra/update-runner.test.ts +++ b/src/infra/update-runner.test.ts @@ -171,7 +171,11 @@ describe("runGatewayUpdate", () => { expect(calls.some((call) => call.startsWith("npm i -g"))).toBe(false); }); - it("updates global npm installs when detected", async () => { + async function runNpmGlobalUpdateCase(params: { + expectedInstallCommand: string; + channel?: "stable" | "beta"; + tag?: string; + }): Promise<{ calls: string[]; result: Awaited> }> { const nodeModules = path.join(tempDir, "node_modules"); const pkgRoot = path.join(nodeModules, "openclaw"); await fs.mkdir(pkgRoot, { recursive: true }); @@ -191,7 +195,7 @@ describe("runGatewayUpdate", () => { if (key === "npm root -g") { return { stdout: nodeModules, stderr: "", code: 0 }; } - if (key === "npm i -g openclaw@latest") { + if (key === params.expectedInstallCommand) { await fs.writeFile( path.join(pkgRoot, "package.json"), JSON.stringify({ name: "openclaw", version: "2.0.0" }), @@ -209,61 +213,40 @@ describe("runGatewayUpdate", () => { cwd: pkgRoot, runCommand: async (argv, _options) => runCommand(argv), timeoutMs: 5000, + channel: params.channel, + tag: params.tag, + }); + + return { calls, result }; + } + + it.each([ + { + title: "updates global npm installs when detected", + expectedInstallCommand: "npm i -g openclaw@latest", + }, + { + title: "uses update channel for global npm installs when tag is omitted", + expectedInstallCommand: "npm i -g openclaw@beta", + channel: "beta" as const, + }, + { + title: "updates global npm installs with tag override", + expectedInstallCommand: "npm i -g openclaw@beta", + tag: "beta", + }, + ])("$title", async ({ expectedInstallCommand, channel, tag }) => { + const { calls, result } = await runNpmGlobalUpdateCase({ + expectedInstallCommand, + channel, + tag, }); expect(result.status).toBe("ok"); expect(result.mode).toBe("npm"); expect(result.before?.version).toBe("1.0.0"); expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "npm i -g openclaw@latest")).toBe(true); - }); - - it("uses update channel for global npm installs when tag is omitted", async () => { - const nodeModules = path.join(tempDir, "node_modules"); - const pkgRoot = path.join(nodeModules, "openclaw"); - await fs.mkdir(pkgRoot, { recursive: true }); - await fs.writeFile( - path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "openclaw", version: "1.0.0" }), - "utf-8", - ); - - const calls: string[] = []; - const runCommand = async (argv: string[]) => { - const key = argv.join(" "); - calls.push(key); - if (key === `git -C ${pkgRoot} rev-parse --show-toplevel`) { - return { stdout: "", stderr: "not a git repository", code: 128 }; - } - if (key === "npm root -g") { - return { stdout: nodeModules, stderr: "", code: 0 }; - } - if (key === "npm i -g openclaw@beta") { - await fs.writeFile( - path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "openclaw", version: "2.0.0" }), - "utf-8", - ); - return { stdout: "ok", stderr: "", code: 0 }; - } - if (key === "pnpm root -g") { - return { stdout: "", stderr: "", code: 1 }; - } - return { stdout: "", stderr: "", code: 0 }; - }; - - const result = await runGatewayUpdate({ - cwd: pkgRoot, - runCommand: async (argv, _options) => runCommand(argv), - timeoutMs: 5000, - channel: "beta", - }); - - expect(result.status).toBe("ok"); - expect(result.mode).toBe("npm"); - expect(result.before?.version).toBe("1.0.0"); - expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "npm i -g openclaw@beta")).toBe(true); + expect(calls.some((call) => call === expectedInstallCommand)).toBe(true); }); it("cleans stale npm rename dirs before global update", async () => { @@ -308,54 +291,6 @@ describe("runGatewayUpdate", () => { expect(await pathExists(staleDir)).toBe(false); }); - it("updates global npm installs with tag override", async () => { - const nodeModules = path.join(tempDir, "node_modules"); - const pkgRoot = path.join(nodeModules, "openclaw"); - await fs.mkdir(pkgRoot, { recursive: true }); - await fs.writeFile( - path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "openclaw", version: "1.0.0" }), - "utf-8", - ); - - const calls: string[] = []; - const runCommand = async (argv: string[]) => { - const key = argv.join(" "); - calls.push(key); - if (key === `git -C ${pkgRoot} rev-parse --show-toplevel`) { - return { stdout: "", stderr: "not a git repository", code: 128 }; - } - if (key === "npm root -g") { - return { stdout: nodeModules, stderr: "", code: 0 }; - } - if (key === "npm i -g openclaw@beta") { - await fs.writeFile( - path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "openclaw", version: "2.0.0" }), - "utf-8", - ); - return { stdout: "ok", stderr: "", code: 0 }; - } - if (key === "pnpm root -g") { - return { stdout: "", stderr: "", code: 1 }; - } - return { stdout: "", stderr: "", code: 0 }; - }; - - const result = await runGatewayUpdate({ - cwd: pkgRoot, - runCommand: async (argv, _options) => runCommand(argv), - timeoutMs: 5000, - tag: "beta", - }); - - expect(result.status).toBe("ok"); - expect(result.mode).toBe("npm"); - expect(result.before?.version).toBe("1.0.0"); - expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "npm i -g openclaw@beta")).toBe(true); - }); - it("updates global bun installs when detected", async () => { const oldBunInstall = process.env.BUN_INSTALL; const bunInstall = path.join(tempDir, "bun-install");