mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-29 02:41:07 +00:00
192 lines
5.3 KiB
TypeScript
192 lines
5.3 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import type { OpenClawConfig } from "../config/config.js";
|
|
import {
|
|
buildPluginStatusReport,
|
|
loadConfig,
|
|
parseClawHubPluginSpec,
|
|
promptYesNo,
|
|
resetPluginsCliTestState,
|
|
runPluginsCommand,
|
|
runtimeErrors,
|
|
runtimeLogs,
|
|
uninstallPlugin,
|
|
writeConfigFile,
|
|
} from "./plugins-cli-test-helpers.js";
|
|
|
|
describe("plugins cli uninstall", () => {
|
|
beforeEach(() => {
|
|
resetPluginsCliTestState();
|
|
});
|
|
|
|
it("shows uninstall dry-run preview without mutating config", async () => {
|
|
loadConfig.mockReturnValue({
|
|
plugins: {
|
|
entries: {
|
|
alpha: {
|
|
enabled: true,
|
|
},
|
|
},
|
|
installs: {
|
|
alpha: {
|
|
source: "path",
|
|
sourcePath: "/tmp/openclaw-state/extensions/alpha",
|
|
installPath: "/tmp/openclaw-state/extensions/alpha",
|
|
},
|
|
},
|
|
},
|
|
} as OpenClawConfig);
|
|
buildPluginStatusReport.mockReturnValue({
|
|
plugins: [{ id: "alpha", name: "alpha" }],
|
|
diagnostics: [],
|
|
});
|
|
|
|
await runPluginsCommand(["plugins", "uninstall", "alpha", "--dry-run"]);
|
|
|
|
expect(uninstallPlugin).not.toHaveBeenCalled();
|
|
expect(writeConfigFile).not.toHaveBeenCalled();
|
|
expect(runtimeLogs.some((line) => line.includes("Dry run, no changes made."))).toBe(true);
|
|
});
|
|
|
|
it("uninstalls with --force and --keep-files without prompting", async () => {
|
|
const baseConfig = {
|
|
plugins: {
|
|
entries: {
|
|
alpha: { enabled: true },
|
|
},
|
|
installs: {
|
|
alpha: {
|
|
source: "path",
|
|
sourcePath: "/tmp/openclaw-state/extensions/alpha",
|
|
installPath: "/tmp/openclaw-state/extensions/alpha",
|
|
},
|
|
},
|
|
},
|
|
} as OpenClawConfig;
|
|
const nextConfig = {
|
|
plugins: {
|
|
entries: {},
|
|
installs: {},
|
|
},
|
|
} as OpenClawConfig;
|
|
|
|
loadConfig.mockReturnValue(baseConfig);
|
|
buildPluginStatusReport.mockReturnValue({
|
|
plugins: [{ id: "alpha", name: "alpha" }],
|
|
diagnostics: [],
|
|
});
|
|
uninstallPlugin.mockResolvedValue({
|
|
ok: true,
|
|
config: nextConfig,
|
|
warnings: [],
|
|
actions: {
|
|
entry: true,
|
|
install: true,
|
|
allowlist: false,
|
|
loadPath: false,
|
|
memorySlot: false,
|
|
directory: false,
|
|
},
|
|
});
|
|
|
|
await runPluginsCommand(["plugins", "uninstall", "alpha", "--force", "--keep-files"]);
|
|
|
|
expect(promptYesNo).not.toHaveBeenCalled();
|
|
expect(uninstallPlugin).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
pluginId: "alpha",
|
|
deleteFiles: false,
|
|
}),
|
|
);
|
|
expect(writeConfigFile).toHaveBeenCalledWith(nextConfig);
|
|
});
|
|
|
|
it("exits when uninstall target is not managed by plugin install records", async () => {
|
|
loadConfig.mockReturnValue({
|
|
plugins: {
|
|
entries: {},
|
|
installs: {},
|
|
},
|
|
} as OpenClawConfig);
|
|
buildPluginStatusReport.mockReturnValue({
|
|
plugins: [{ id: "alpha", name: "alpha" }],
|
|
diagnostics: [],
|
|
});
|
|
|
|
await expect(runPluginsCommand(["plugins", "uninstall", "alpha", "--force"])).rejects.toThrow(
|
|
"__exit__:1",
|
|
);
|
|
|
|
expect(runtimeErrors.at(-1)).toContain("is not managed by plugins config/install records");
|
|
expect(uninstallPlugin).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("accepts the recorded ClawHub spec as an uninstall target", async () => {
|
|
loadConfig.mockReturnValue({
|
|
plugins: {
|
|
entries: {
|
|
"linkmind-context": { enabled: true },
|
|
},
|
|
installs: {
|
|
"linkmind-context": {
|
|
source: "npm",
|
|
spec: "clawhub:linkmind-context",
|
|
clawhubPackage: "linkmind-context",
|
|
},
|
|
},
|
|
},
|
|
} as OpenClawConfig);
|
|
buildPluginStatusReport.mockReturnValue({
|
|
plugins: [{ id: "linkmind-context", name: "linkmind-context" }],
|
|
diagnostics: [],
|
|
});
|
|
parseClawHubPluginSpec.mockImplementation((raw: string) =>
|
|
raw === "clawhub:linkmind-context" ? { name: "linkmind-context" } : null,
|
|
);
|
|
|
|
await runPluginsCommand(["plugins", "uninstall", "clawhub:linkmind-context", "--force"]);
|
|
|
|
expect(uninstallPlugin).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
pluginId: "linkmind-context",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("accepts a versionless ClawHub spec when the install was pinned", async () => {
|
|
loadConfig.mockReturnValue({
|
|
plugins: {
|
|
entries: {
|
|
"linkmind-context": { enabled: true },
|
|
},
|
|
installs: {
|
|
"linkmind-context": {
|
|
source: "npm",
|
|
spec: "clawhub:linkmind-context@1.2.3",
|
|
},
|
|
},
|
|
},
|
|
} as OpenClawConfig);
|
|
buildPluginStatusReport.mockReturnValue({
|
|
plugins: [{ id: "linkmind-context", name: "linkmind-context" }],
|
|
diagnostics: [],
|
|
});
|
|
parseClawHubPluginSpec.mockImplementation((raw: string) => {
|
|
if (raw === "clawhub:linkmind-context") {
|
|
return { name: "linkmind-context" };
|
|
}
|
|
if (raw === "clawhub:linkmind-context@1.2.3") {
|
|
return { name: "linkmind-context", version: "1.2.3" };
|
|
}
|
|
return null;
|
|
});
|
|
|
|
await runPluginsCommand(["plugins", "uninstall", "clawhub:linkmind-context", "--force"]);
|
|
|
|
expect(uninstallPlugin).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
pluginId: "linkmind-context",
|
|
}),
|
|
);
|
|
});
|
|
});
|