























@@ -0,0 +1,116 @@
1+import { afterEach, describe, expect, it, vi } from "vitest";
2+import type { PluginInstallRecord } from "../config/types.plugins.js";
3+import type { PluginCandidate, PluginDiscoveryResult } from "./discovery.js";
4+5+afterEach(() => {
6+vi.restoreAllMocks();
7+vi.resetModules();
8+vi.doUnmock("./discovery.js");
9+vi.doUnmock("./installed-plugin-index-record-reader.js");
10+});
11+12+const ENV: NodeJS.ProcessEnv = { HOME: "/tmp/openclaw-test-home" };
13+14+const RECORDS: Record<string, PluginInstallRecord> = {
15+weixin: {
16+source: "npm",
17+spec: "@tencent-weixin/openclaw-weixin@2.3.7",
18+installPath:
19+"/tmp/openclaw-test-home/.openclaw/npm/node_modules/@tencent-weixin/openclaw-weixin",
20+} as PluginInstallRecord,
21+};
22+23+function emptyDiscoveryResult(): PluginDiscoveryResult {
24+return {
25+candidates: [] as PluginCandidate[],
26+diagnostics: [],
27+};
28+}
29+30+async function loadWithMocks(params: {
31+loadRecords?: (env: NodeJS.ProcessEnv | undefined) => Record<string, PluginInstallRecord>;
32+}): Promise<{
33+module: typeof import("./channel-catalog-registry.js");
34+discoverSpy: ReturnType<typeof vi.fn>;
35+loadRecordsSpy: ReturnType<typeof vi.fn>;
36+}> {
37+vi.resetModules();
38+const discoverSpy = vi.fn(() => emptyDiscoveryResult());
39+const loadRecordsSpy = vi.fn((opts: { env?: NodeJS.ProcessEnv } = {}) => {
40+return params.loadRecords ? params.loadRecords(opts.env) : RECORDS;
41+});
42+43+vi.doMock("./discovery.js", () => ({ discoverOpenClawPlugins: discoverSpy }));
44+vi.doMock("./installed-plugin-index-record-reader.js", () => ({
45+loadInstalledPluginIndexInstallRecordsSync: loadRecordsSpy,
46+}));
47+48+const module = await import("./channel-catalog-registry.js");
49+return { module, discoverSpy, loadRecordsSpy };
50+}
51+52+describe("listChannelCatalogEntries", () => {
53+it("forwards lazily loaded install records to discovery when origin is unspecified", async () => {
54+const { module, discoverSpy, loadRecordsSpy } = await loadWithMocks({});
55+56+module.listChannelCatalogEntries({ env: ENV });
57+58+expect(loadRecordsSpy).toHaveBeenCalledTimes(1);
59+expect(loadRecordsSpy).toHaveBeenCalledWith({ env: ENV });
60+expect(discoverSpy).toHaveBeenCalledTimes(1);
61+expect(discoverSpy.mock.calls[0][0]).toMatchObject({
62+env: ENV,
63+installRecords: RECORDS,
64+});
65+});
66+67+it("skips ledger lookup when origin is 'bundled' and omits installRecords", async () => {
68+const { module, discoverSpy, loadRecordsSpy } = await loadWithMocks({});
69+70+module.listChannelCatalogEntries({ origin: "bundled", env: ENV });
71+72+expect(loadRecordsSpy).not.toHaveBeenCalled();
73+expect(discoverSpy).toHaveBeenCalledTimes(1);
74+expect(discoverSpy.mock.calls[0][0]).not.toHaveProperty("installRecords");
75+});
76+77+it("uses caller-supplied install records verbatim and does not load the ledger", async () => {
78+const { module, discoverSpy, loadRecordsSpy } = await loadWithMocks({});
79+const supplied: Record<string, PluginInstallRecord> = {
80+slack: {
81+source: "npm",
82+spec: "@openclaw/slack@1.0.0",
83+} as PluginInstallRecord,
84+};
85+86+module.listChannelCatalogEntries({ env: ENV, installRecords: supplied });
87+88+expect(loadRecordsSpy).not.toHaveBeenCalled();
89+expect(discoverSpy.mock.calls[0][0]).toMatchObject({ installRecords: supplied });
90+});
91+92+it("omits installRecords from discovery when the ledger is empty", async () => {
93+const { module, discoverSpy, loadRecordsSpy } = await loadWithMocks({
94+loadRecords: () => ({}),
95+});
96+97+module.listChannelCatalogEntries({ env: ENV });
98+99+expect(loadRecordsSpy).toHaveBeenCalledTimes(1);
100+expect(discoverSpy.mock.calls[0][0]).not.toHaveProperty("installRecords");
101+});
102+103+it("treats ledger read errors as a soft fallback (no installRecords propagated)", async () => {
104+const { module, discoverSpy, loadRecordsSpy } = await loadWithMocks({
105+loadRecords: () => {
106+throw new Error("simulated reader failure");
107+},
108+});
109+110+expect(() => module.listChannelCatalogEntries({ env: ENV })).not.toThrow();
111+112+expect(loadRecordsSpy).toHaveBeenCalledTimes(1);
113+expect(discoverSpy).toHaveBeenCalledTimes(1);
114+expect(discoverSpy.mock.calls[0][0]).not.toHaveProperty("installRecords");
115+});
116+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。