mirror of https://github.com/openclaw/openclaw.git
test: add clipboard and package helper coverage
This commit is contained in:
parent
ba9fb4d994
commit
c84c76ee66
|
|
@ -0,0 +1,52 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runCommandWithTimeoutMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../process/exec.js", () => ({
|
||||
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
|
||||
}));
|
||||
|
||||
const { copyToClipboard } = await import("./clipboard.js");
|
||||
|
||||
describe("copyToClipboard", () => {
|
||||
beforeEach(() => {
|
||||
runCommandWithTimeoutMock.mockReset();
|
||||
});
|
||||
|
||||
it("returns true on the first successful clipboard command", async () => {
|
||||
runCommandWithTimeoutMock.mockResolvedValueOnce({ code: 0, killed: false });
|
||||
|
||||
await expect(copyToClipboard("hello")).resolves.toBe(true);
|
||||
expect(runCommandWithTimeoutMock).toHaveBeenCalledWith(["pbcopy"], {
|
||||
timeoutMs: 3000,
|
||||
input: "hello",
|
||||
});
|
||||
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("falls through failed attempts until a later command succeeds", async () => {
|
||||
runCommandWithTimeoutMock
|
||||
.mockRejectedValueOnce(new Error("missing pbcopy"))
|
||||
.mockResolvedValueOnce({ code: 1, killed: false })
|
||||
.mockResolvedValueOnce({ code: 0, killed: false });
|
||||
|
||||
await expect(copyToClipboard("hello")).resolves.toBe(true);
|
||||
expect(runCommandWithTimeoutMock.mock.calls.map((call) => call[0])).toEqual([
|
||||
["pbcopy"],
|
||||
["xclip", "-selection", "clipboard"],
|
||||
["wl-copy"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns false when every clipboard backend fails or is killed", async () => {
|
||||
runCommandWithTimeoutMock
|
||||
.mockResolvedValueOnce({ code: 0, killed: true })
|
||||
.mockRejectedValueOnce(new Error("missing xclip"))
|
||||
.mockResolvedValueOnce({ code: 1, killed: false })
|
||||
.mockRejectedValueOnce(new Error("missing clip.exe"))
|
||||
.mockResolvedValueOnce({ code: 2, killed: false });
|
||||
|
||||
await expect(copyToClipboard("hello")).resolves.toBe(false);
|
||||
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(5);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { normalizePackageTagInput } from "./package-tag.js";
|
||||
|
||||
describe("normalizePackageTagInput", () => {
|
||||
const packageNames = ["openclaw", "@openclaw/plugin"] as const;
|
||||
|
||||
it("returns null for blank inputs", () => {
|
||||
expect(normalizePackageTagInput(undefined, packageNames)).toBeNull();
|
||||
expect(normalizePackageTagInput(" ", packageNames)).toBeNull();
|
||||
});
|
||||
|
||||
it("strips known package-name prefixes before returning the tag", () => {
|
||||
expect(normalizePackageTagInput("openclaw@beta", packageNames)).toBe("beta");
|
||||
expect(normalizePackageTagInput("@openclaw/plugin@2026.2.24", packageNames)).toBe("2026.2.24");
|
||||
});
|
||||
|
||||
it("returns trimmed raw values when no package prefix matches", () => {
|
||||
expect(normalizePackageTagInput(" latest ", packageNames)).toBe("latest");
|
||||
expect(normalizePackageTagInput("@other/plugin@beta", packageNames)).toBe("@other/plugin@beta");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveStableNodePath } from "./stable-node-path.js";
|
||||
|
||||
describe("resolveStableNodePath", () => {
|
||||
it("returns non-cellar paths unchanged", async () => {
|
||||
await expect(resolveStableNodePath("/usr/local/bin/node")).resolves.toBe("/usr/local/bin/node");
|
||||
});
|
||||
|
||||
it("prefers the Homebrew opt symlink for default and versioned formulas", async () => {
|
||||
const prefix = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-stable-node-"));
|
||||
const defaultNode = path.join(prefix, "Cellar", "node", "25.7.0", "bin", "node");
|
||||
const versionedNode = path.join(prefix, "Cellar", "node@22", "22.17.0", "bin", "node");
|
||||
const optDefault = path.join(prefix, "opt", "node", "bin", "node");
|
||||
const optVersioned = path.join(prefix, "opt", "node@22", "bin", "node");
|
||||
|
||||
await fs.mkdir(path.dirname(optDefault), { recursive: true });
|
||||
await fs.mkdir(path.dirname(optVersioned), { recursive: true });
|
||||
await fs.writeFile(optDefault, "", "utf8");
|
||||
await fs.writeFile(optVersioned, "", "utf8");
|
||||
|
||||
await expect(resolveStableNodePath(defaultNode)).resolves.toBe(optDefault);
|
||||
await expect(resolveStableNodePath(versionedNode)).resolves.toBe(optVersioned);
|
||||
});
|
||||
|
||||
it("falls back to the bin symlink for the default formula, otherwise original path", async () => {
|
||||
const prefix = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-stable-node-"));
|
||||
const defaultNode = path.join(prefix, "Cellar", "node", "25.7.0", "bin", "node");
|
||||
const versionedNode = path.join(prefix, "Cellar", "node@22", "22.17.0", "bin", "node");
|
||||
const binNode = path.join(prefix, "bin", "node");
|
||||
|
||||
await fs.mkdir(path.dirname(binNode), { recursive: true });
|
||||
await fs.writeFile(binNode, "", "utf8");
|
||||
|
||||
await expect(resolveStableNodePath(defaultNode)).resolves.toBe(binNode);
|
||||
await expect(resolveStableNodePath(versionedNode)).resolves.toBe(versionedNode);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue