mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 14:10:43 +00:00
Summary: - The branch adds ClawHub plugin search and Crestodian plugin list/search/install/uninstall flows, with docs, changelog, tests, runtime injection, and regenerated config baseline hashes. - Reproducibility: not applicable. as a bug reproduction request. The high-confidence verification path is cur ... surface search plus exact-head diff/source inspection against the PR's targeted tests and queued CI checks. ClawSweeper fixups: - Included follow-up commit: Repair Crestodian plugin management config schema drift Validation: - ClawSweeper review passed for headc29cda6005. - Required merge gates passed before the squash merge. Prepared head SHA:c29cda6005Review: https://github.com/openclaw/openclaw/pull/75869#issuecomment-4362360704 Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
111 lines
3.2 KiB
TypeScript
111 lines
3.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => {
|
|
const logs: string[] = [];
|
|
const errors: string[] = [];
|
|
const runtime = {
|
|
log: vi.fn((value: unknown) => logs.push(String(value))),
|
|
error: vi.fn((value: unknown) => errors.push(String(value))),
|
|
writeJson: vi.fn((value: unknown, space = 2) =>
|
|
logs.push(JSON.stringify(value, null, space > 0 ? space : undefined)),
|
|
),
|
|
writeStdout: vi.fn((value: string) =>
|
|
logs.push(value.endsWith("\n") ? value.slice(0, -1) : value),
|
|
),
|
|
exit: vi.fn((code: number) => {
|
|
throw new Error(`__exit__:${code}`);
|
|
}),
|
|
};
|
|
return {
|
|
logs,
|
|
errors,
|
|
runtime,
|
|
searchClawHubPackages: vi.fn(),
|
|
};
|
|
});
|
|
|
|
vi.mock("../runtime.js", () => ({
|
|
defaultRuntime: mocks.runtime,
|
|
writeRuntimeJson: (runtime: typeof mocks.runtime, value: unknown, space = 2) =>
|
|
runtime.writeJson(value, space),
|
|
}));
|
|
|
|
vi.mock("../infra/clawhub.js", () => ({
|
|
searchClawHubPackages: mocks.searchClawHubPackages,
|
|
}));
|
|
|
|
const { runPluginsSearchCommand } = await import("./plugins-search-command.js");
|
|
|
|
describe("plugins search command", () => {
|
|
beforeEach(() => {
|
|
mocks.logs.length = 0;
|
|
mocks.errors.length = 0;
|
|
mocks.runtime.log.mockClear();
|
|
mocks.runtime.error.mockClear();
|
|
mocks.runtime.writeJson.mockClear();
|
|
mocks.runtime.exit.mockClear();
|
|
mocks.searchClawHubPackages.mockReset();
|
|
});
|
|
|
|
it("searches ClawHub code and bundle plugin families", async () => {
|
|
mocks.searchClawHubPackages
|
|
.mockResolvedValueOnce([
|
|
{
|
|
score: 12,
|
|
package: {
|
|
name: "openclaw-calendar",
|
|
displayName: "Calendar",
|
|
family: "code-plugin",
|
|
channel: "community",
|
|
isOfficial: false,
|
|
summary: "Calendar sync",
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
latestVersion: "1.2.3",
|
|
},
|
|
},
|
|
])
|
|
.mockResolvedValueOnce([
|
|
{
|
|
score: 10,
|
|
package: {
|
|
name: "openclaw-calendar-bundle",
|
|
displayName: "Calendar Bundle",
|
|
family: "bundle-plugin",
|
|
channel: "official",
|
|
isOfficial: true,
|
|
summary: "Calendar bundle",
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
latestVersion: "2.0.0",
|
|
},
|
|
},
|
|
]);
|
|
|
|
await runPluginsSearchCommand(["calendar"], { limit: 5 }, mocks.runtime);
|
|
|
|
expect(mocks.searchClawHubPackages).toHaveBeenCalledWith({
|
|
query: "calendar",
|
|
family: "code-plugin",
|
|
limit: 5,
|
|
});
|
|
expect(mocks.searchClawHubPackages).toHaveBeenCalledWith({
|
|
query: "calendar",
|
|
family: "bundle-plugin",
|
|
limit: 5,
|
|
});
|
|
expect(mocks.logs.join("\n")).toContain("openclaw-calendar");
|
|
expect(mocks.logs.join("\n")).toContain(
|
|
"Install: openclaw plugins install clawhub:openclaw-calendar",
|
|
);
|
|
});
|
|
|
|
it("writes JSON results when requested", async () => {
|
|
mocks.searchClawHubPackages.mockResolvedValueOnce([]).mockResolvedValueOnce([]);
|
|
|
|
await runPluginsSearchCommand("calendar", { json: true }, mocks.runtime);
|
|
|
|
expect(mocks.runtime.writeJson).toHaveBeenCalledWith({ results: [] }, 2);
|
|
});
|
|
});
|