





















@@ -180,6 +180,20 @@ function stalePluginConfig(id = "acpx") {
180180};
181181}
182182183+function expectSingleWarningContaining(warnings: string[], text: string): string {
184+expect(warnings).toHaveLength(1);
185+const warning = warnings[0];
186+expect(warning).toContain(text);
187+return warning;
188+}
189+190+function expectWarningsContaining(warnings: string[], texts: string[]): void {
191+expect(warnings).toHaveLength(texts.length);
192+texts.forEach((text, index) => {
193+expect(warnings[index]).toContain(text);
194+});
195+}
196+183197describe("doctor preview warnings", () => {
184198beforeEach(() => {
185199manifestState.plugins = [manifest("discord")];
@@ -232,11 +246,12 @@ describe("doctor preview warnings", () => {
232246doctorFixCommand: "openclaw doctor --fix",
233247});
234248235-expect(warnings).toEqual([
236-expect.stringContaining("channels.signal.accounts.ops-teamnext.dmPolicy"),
237-]);
238-expect(warnings[0]).not.toContain("\u001B");
239-expect(warnings[0]).not.toContain("\r");
249+const warning = expectSingleWarningContaining(
250+warnings,
251+"channels.signal.accounts.ops-teamnext.dmPolicy",
252+);
253+expect(warning).not.toContain("\u001B");
254+expect(warning).not.toContain("\r");
240255});
241256242257it("includes stale plugin config warnings", async () => {
@@ -245,12 +260,13 @@ describe("doctor preview warnings", () => {
245260doctorFixCommand: "openclaw doctor --fix",
246261});
247262248-expect(warnings).toEqual([
249-expect.stringContaining('plugins.allow: stale plugin reference "acpx"'),
250-]);
251-expect(warnings[0]).toContain("plugins.entries.acpx");
252-expect(warnings[0]).toContain('Run "openclaw doctor --fix"');
253-expect(warnings[0]).not.toContain("Auto-removal is paused");
263+const warning = expectSingleWarningContaining(
264+warnings,
265+'plugins.allow: stale plugin reference "acpx"',
266+);
267+expect(warning).toContain("plugins.entries.acpx");
268+expect(warning).toContain('Run "openclaw doctor --fix"');
269+expect(warning).not.toContain("Auto-removal is paused");
254270});
255271256272it("includes stale channel config warnings without plugin config", async () => {
@@ -265,9 +281,7 @@ describe("doctor preview warnings", () => {
265281doctorFixCommand: "openclaw doctor --fix",
266282});
267283268-expect(warnings).toEqual([
269-expect.stringContaining("channels.openclaw-weixin: dangling channel config"),
270-]);
284+expectSingleWarningContaining(warnings, "channels.openclaw-weixin: dangling channel config");
271285});
272286273287it("includes bundled plugin load path migration warnings", async () => {
@@ -286,10 +300,11 @@ describe("doctor preview warnings", () => {
286300doctorFixCommand: "openclaw doctor --fix",
287301});
288302289-expect(warnings).toEqual([
290-expect.stringContaining(`plugins.load.paths: legacy bundled plugin path "${legacyPath}"`),
291-]);
292-expect(warnings[0]).toContain('Run "openclaw doctor --fix"');
303+const warning = expectSingleWarningContaining(
304+warnings,
305+`plugins.load.paths: legacy bundled plugin path "${legacyPath}"`,
306+);
307+expect(warning).toContain('Run "openclaw doctor --fix"');
293308});
294309295310it("warns but skips auto-removal when plugin discovery has errors", async () => {
@@ -303,11 +318,12 @@ describe("doctor preview warnings", () => {
303318doctorFixCommand: "openclaw doctor --fix",
304319});
305320306-expect(warnings).toEqual([
307-expect.stringContaining('plugins.allow: stale plugin reference "acpx"'),
308-]);
309-expect(warnings[0]).toContain("Auto-removal is paused");
310-expect(warnings[0]).toContain('rerun "openclaw doctor --fix"');
321+const warning = expectSingleWarningContaining(
322+warnings,
323+'plugins.allow: stale plugin reference "acpx"',
324+);
325+expect(warning).toContain("Auto-removal is paused");
326+expect(warning).toContain('rerun "openclaw doctor --fix"');
311327});
312328313329it("warns when a configured channel plugin is disabled explicitly", async () => {
@@ -332,12 +348,11 @@ describe("doctor preview warnings", () => {
332348doctorFixCommand: "openclaw doctor --fix",
333349});
334350335-expect(warnings).toEqual([
336-expect.stringContaining(
337-'channels.telegram: channel is configured, but plugin "telegram" is disabled by plugins.entries.telegram.enabled=false.',
338-),
339-]);
340-expect(warnings[0]).not.toContain("first-time setup mode");
351+const warning = expectSingleWarningContaining(
352+warnings,
353+'channels.telegram: channel is configured, but plugin "telegram" is disabled by plugins.entries.telegram.enabled=false.',
354+);
355+expect(warning).not.toContain("first-time setup mode");
341356});
342357343358it("warns when channel plugins are blocked globally", async () => {
@@ -358,12 +373,11 @@ describe("doctor preview warnings", () => {
358373doctorFixCommand: "openclaw doctor --fix",
359374});
360375361-expect(warnings).toEqual([
362-expect.stringContaining(
363-"channels.telegram: channel is configured, but plugins.enabled=false blocks channel plugins globally.",
364-),
365-]);
366-expect(warnings[0]).not.toContain("first-time setup mode");
376+const warning = expectSingleWarningContaining(
377+warnings,
378+"channels.telegram: channel is configured, but plugins.enabled=false blocks channel plugins globally.",
379+);
380+expect(warning).not.toContain("first-time setup mode");
367381});
368382369383it("keeps global plugin-disable blocker warnings but omits stale plugin cleanup warnings", async () => {
@@ -388,11 +402,10 @@ describe("doctor preview warnings", () => {
388402doctorFixCommand: "openclaw doctor --fix",
389403});
390404391-expect(warnings).toEqual([
392-expect.stringContaining(
393-"channels.telegram: channel is configured, but plugins.enabled=false blocks channel plugins globally.",
394-),
395-]);
405+expectSingleWarningContaining(
406+warnings,
407+"channels.telegram: channel is configured, but plugins.enabled=false blocks channel plugins globally.",
408+);
396409expect(warnings.join("\n")).not.toContain("stale plugin reference");
397410});
398411@@ -406,11 +419,12 @@ describe("doctor preview warnings", () => {
406419},
407420});
408421409-expect(warnings).toEqual([
410-expect.stringContaining('messages.groupChat.visibleReplies defaults to "message_tool"'),
411-]);
412-expect(warnings[0]).toContain("message tool is unavailable");
413-expect(warnings[0]).toContain("falls back to automatic group/channel replies");
422+const warning = expectSingleWarningContaining(
423+warnings,
424+'messages.groupChat.visibleReplies defaults to "message_tool"',
425+);
426+expect(warning).toContain("message tool is unavailable");
427+expect(warning).toContain("falls back to automatic group/channel replies");
414428});
415429416430it("warns strongly when explicit group visible replies require an unavailable message tool", () => {
@@ -425,11 +439,12 @@ describe("doctor preview warnings", () => {
425439},
426440});
427441428-expect(warnings).toEqual([
429-expect.stringContaining('messages.groupChat.visibleReplies is set to "message_tool"'),
430-]);
431-expect(warnings[0]).toContain("normal replies may post to the source chat");
432-expect(warnings[0]).toContain('set messages.groupChat.visibleReplies to "automatic"');
442+const warning = expectSingleWarningContaining(
443+warnings,
444+'messages.groupChat.visibleReplies is set to "message_tool"',
445+);
446+expect(warning).toContain("normal replies may post to the source chat");
447+expect(warning).toContain('set messages.groupChat.visibleReplies to "automatic"');
433448});
434449435450it("warns for direct chats when global visible replies are tool-only but groups override automatic", () => {
@@ -445,10 +460,11 @@ describe("doctor preview warnings", () => {
445460},
446461});
447462448-expect(warnings).toEqual([
449-expect.stringContaining('messages.visibleReplies is set to "message_tool"'),
450-]);
451-expect(warnings[0]).toContain("automatic direct-chat replies");
463+const warning = expectSingleWarningContaining(
464+warnings,
465+'messages.visibleReplies is set to "message_tool"',
466+);
467+expect(warning).toContain("automatic direct-chat replies");
452468});
453469454470it("warns separately for explicit global and group visible reply policy mismatches", () => {
@@ -464,9 +480,9 @@ describe("doctor preview warnings", () => {
464480},
465481});
466482467-expect(warnings).toEqual([
468-expect.stringContaining('messages.groupChat.visibleReplies is set to "message_tool"'),
469-expect.stringContaining('messages.visibleReplies is set to "message_tool"'),
483+expectWarningsContaining(warnings, [
484+'messages.groupChat.visibleReplies is set to "message_tool"',
485+'messages.visibleReplies is set to "message_tool"',
470486]);
471487});
472488此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。