


























@@ -344,6 +344,20 @@ function clawHubInstallCall(index = 0): Record<string, unknown> | undefined {
344344return calls[index]?.[0];
345345}
346346347+function marketplaceInstallCall(index = 0): Record<string, unknown> | undefined {
348+const calls = installPluginFromMarketplaceMock.mock.calls as unknown as Array<
349+[Record<string, unknown>]
350+>;
351+return calls[index]?.[0];
352+}
353+354+function gitInstallCall(index = 0): Record<string, unknown> | undefined {
355+const calls = installPluginFromGitSpecMock.mock.calls as unknown as Array<
356+[Record<string, unknown>]
357+>;
358+return calls[index]?.[0];
359+}
360+347361function npmViewCall(): [unknown, Record<string, unknown>] | undefined {
348362const calls = runCommandWithTimeoutMock.mock.calls as unknown as Array<
349363[unknown, Record<string, unknown>]
@@ -2267,13 +2281,10 @@ describe("updateNpmInstalledPlugins", () => {
2267228122682282expect(installPluginFromClawHubMock).not.toHaveBeenCalled();
22692283expect(result.changed).toBe(false);
2270-expect(result.outcomes).toEqual([
2271-expect.objectContaining({
2272-pluginId: "whatsapp",
2273-status: "skipped",
2274-message: expect.stringContaining("bundled version 2026.4.20 is newer"),
2275-}),
2276-]);
2284+expect(result.outcomes).toHaveLength(1);
2285+expect(result.outcomes[0]?.pluginId).toBe("whatsapp");
2286+expect(result.outcomes[0]?.status).toBe("skipped");
2287+expect(result.outcomes[0]?.message).toContain("bundled version 2026.4.20 is newer");
22772288expect(warnMessages).toEqual([expect.stringContaining("bundled version 2026.4.20 is newer")]);
22782289});
22792290@@ -2405,12 +2416,8 @@ describe("updateNpmInstalledPlugins", () => {
24052416pluginIds: ["voice-call"],
24062417});
240724182408-expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
2409-expect.objectContaining({
2410-spec: "@openclaw/voice-call",
2411-expectedPluginId: "voice-call",
2412-}),
2413-);
2419+expect(npmInstallCall()?.spec).toBe("@openclaw/voice-call");
2420+expect(npmInstallCall()?.expectedPluginId).toBe("voice-call");
24142421expect(result.config.plugins?.allow).toEqual(["@openclaw/voice-call"]);
24152422expect(result.config.plugins?.deny).toEqual(["@openclaw/voice-call"]);
24162423expect(result.config.plugins?.slots?.memory).toBe("@openclaw/voice-call");
@@ -2419,7 +2426,7 @@ describe("updateNpmInstalledPlugins", () => {
24192426hooks: { allowPromptInjection: false },
24202427});
24212428expect(result.config.plugins?.entries?.["voice-call"]).toBeUndefined();
2422-expect(result.config.plugins?.installs?.["@openclaw/voice-call"]).toMatchObject({
2429+expectRecordFields(result.config.plugins?.installs?.["@openclaw/voice-call"], {
24232430source: "npm",
24242431spec: "@openclaw/voice-call",
24252432installPath: "/tmp/openclaw-voice-call",
@@ -2454,7 +2461,7 @@ describe("updateNpmInstalledPlugins", () => {
24542461});
2455246224562463expect(result.config.plugins?.slots?.contextEngine).toBe("@openclaw/context-engine");
2457-expect(result.config.plugins?.installs?.["@openclaw/context-engine"]).toMatchObject({
2464+expectRecordFields(result.config.plugins?.installs?.["@openclaw/context-engine"], {
24582465source: "npm",
24592466spec: "@openclaw/context-engine",
24602467installPath: "/tmp/openclaw-context-engine",
@@ -2486,15 +2493,11 @@ describe("updateNpmInstalledPlugins", () => {
24862493dryRun: true,
24872494});
248824952489-expect(installPluginFromMarketplaceMock).toHaveBeenCalledWith(
2490-expect.objectContaining({
2491-marketplace: "vincentkoc/claude-marketplace",
2492-plugin: "claude-bundle",
2493-expectedPluginId: "claude-bundle",
2494-dryRun: true,
2495-timeoutMs: 1_800_000,
2496-}),
2497-);
2496+expect(marketplaceInstallCall()?.marketplace).toBe("vincentkoc/claude-marketplace");
2497+expect(marketplaceInstallCall()?.plugin).toBe("claude-bundle");
2498+expect(marketplaceInstallCall()?.expectedPluginId).toBe("claude-bundle");
2499+expect(marketplaceInstallCall()?.dryRun).toBe(true);
2500+expect(marketplaceInstallCall()?.timeoutMs).toBe(1_800_000);
24982501expect(result.outcomes).toEqual([
24992502{
25002503pluginId: "claude-bundle",
@@ -2530,7 +2533,7 @@ describe("updateNpmInstalledPlugins", () => {
25302533});
2531253425322535expect(result.changed).toBe(true);
2533-expect(result.config.plugins?.installs?.["claude-bundle"]).toMatchObject({
2536+expectRecordFields(result.config.plugins?.installs?.["claude-bundle"], {
25342537source: "marketplace",
25352538installPath: "/tmp/claude-bundle",
25362539version: "1.3.0",
@@ -2565,15 +2568,11 @@ describe("updateNpmInstalledPlugins", () => {
25652568pluginIds: ["demo"],
25662569});
256725702568-expect(installPluginFromGitSpecMock).toHaveBeenCalledWith(
2569-expect.objectContaining({
2570-spec: "git:github.com/acme/demo@main",
2571-expectedPluginId: "demo",
2572-mode: "update",
2573-}),
2574-);
2571+expect(gitInstallCall()?.spec).toBe("git:github.com/acme/demo@main");
2572+expect(gitInstallCall()?.expectedPluginId).toBe("demo");
2573+expect(gitInstallCall()?.mode).toBe("update");
25752574expect(result.changed).toBe(true);
2576-expect(result.config.plugins?.installs?.demo).toMatchObject({
2575+expectRecordFields(result.config.plugins?.installs?.demo, {
25772576source: "git",
25782577spec: "git:github.com/acme/demo@main",
25792578installPath: "/tmp/demo",
@@ -2601,13 +2600,9 @@ describe("updateNpmInstalledPlugins", () => {
26012600dangerouslyForceUnsafeInstall: true,
26022601});
260326022604-expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
2605-expect.objectContaining({
2606-spec: "openclaw-codex-app-server@beta",
2607-dangerouslyForceUnsafeInstall: true,
2608-expectedPluginId: "openclaw-codex-app-server",
2609-}),
2610-);
2603+expect(npmInstallCall()?.spec).toBe("openclaw-codex-app-server@beta");
2604+expect(npmInstallCall()?.dangerouslyForceUnsafeInstall).toBe(true);
2605+expect(npmInstallCall()?.expectedPluginId).toBe("openclaw-codex-app-server");
26112606});
2612260726132608it("reuses the recorded managed extensions root when updating external plugins", async () => {
@@ -2696,18 +2691,10 @@ describe("updateNpmInstalledPlugins", () => {
26962691pluginIds: ["demo"],
26972692});
269826932699-expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
2700-expect.objectContaining({ extensionsDir }),
2701-);
2702-expect(installPluginFromClawHubMock).toHaveBeenCalledWith(
2703-expect.objectContaining({ extensionsDir }),
2704-);
2705-expect(installPluginFromMarketplaceMock).toHaveBeenCalledWith(
2706-expect.objectContaining({ extensionsDir }),
2707-);
2708-expect(installPluginFromGitSpecMock).toHaveBeenCalledWith(
2709-expect.objectContaining({ extensionsDir }),
2710-);
2694+expect(npmInstallCall()?.extensionsDir).toBe(extensionsDir);
2695+expect(clawHubInstallCall()?.extensionsDir).toBe(extensionsDir);
2696+expect(marketplaceInstallCall()?.extensionsDir).toBe(extensionsDir);
2697+expect(gitInstallCall()?.extensionsDir).toBe(extensionsDir);
27112698});
27122699});
27132700此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。