























@@ -43,6 +43,57 @@ function createUnexpectedPromptGuards() {
4343};
4444}
454546+type MockWithCalls = {
47+mock: { calls: unknown[][] };
48+};
49+50+function callArgAt(mock: MockWithCalls, index: number): Record<string, unknown> {
51+const value = mock.mock.calls[index]?.[0];
52+if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
53+throw new Error(`expected call ${index} to receive an object argument`);
54+}
55+return value as Record<string, unknown>;
56+}
57+58+function hasCallWithFields(mock: MockWithCalls, expected: Record<string, unknown>): boolean {
59+return mock.mock.calls.some(([value]) => {
60+if (
61+value === undefined ||
62+value === null ||
63+typeof value !== "object" ||
64+Array.isArray(value)
65+) {
66+return false;
67+}
68+const arg = value as Record<string, unknown>;
69+return Object.entries(expected).every(([key, expectedValue]) => arg[key] === expectedValue);
70+});
71+}
72+73+function expectCalledWithFields(mock: MockWithCalls, expected: Record<string, unknown>): void {
74+expect(hasCallWithFields(mock, expected)).toBe(true);
75+}
76+77+function expectCalledWithMessage(mock: MockWithCalls, message: string): void {
78+expect(hasCallWithFields(mock, { message })).toBe(true);
79+}
80+81+function expectCalledWithMessageContaining(mock: MockWithCalls, text: string): void {
82+const hasMatch = mock.mock.calls.some(([value]) => {
83+if (
84+value === undefined ||
85+value === null ||
86+typeof value !== "object" ||
87+Array.isArray(value)
88+) {
89+return false;
90+}
91+const message = (value as Record<string, unknown>).message;
92+return typeof message === "string" && message.includes(text);
93+});
94+expect(hasMatch).toBe(true);
95+}
96+4697type SetupChannels = typeof import("./onboard-channels.js").setupChannels;
4798let setupChannels: SetupChannels;
4899@@ -714,7 +765,7 @@ describe("setupChannels", () => {
714765715766await runSetupChannels({} as OpenClawConfig, prompter);
716767717-expect(select).toHaveBeenCalledWith(expect.objectContaining({ message: "Select a channel" }));
768+expectCalledWithMessage(select, "Select a channel");
718769expect(multiselect).not.toHaveBeenCalled();
719770});
720771@@ -764,7 +815,7 @@ describe("setupChannels", () => {
764815765816await runSetupChannels({} as OpenClawConfig, prompter);
766817767-expect(select).toHaveBeenCalledWith(expect.objectContaining({ message: "Select a channel" }));
818+expectCalledWithMessage(select, "Select a channel");
768819expect(
769820note.mock.calls.some((call) =>
770821(call[0] ?? "").includes("broken-channel plugin not available"),
@@ -813,12 +864,10 @@ describe("setupChannels", () => {
813864prompter,
814865);
815866816-expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
817-expect.objectContaining({
818-channel: "external-chat",
819-pluginId: "@openclaw/external-chat-plugin",
820-}),
821-);
867+expectCalledWithFields(vi.mocked(loadChannelSetupPluginRegistrySnapshotForChannel), {
868+channel: "external-chat",
869+pluginId: "@openclaw/external-chat-plugin",
870+});
822871expect(multiselect).not.toHaveBeenCalled();
823872});
824873@@ -863,7 +912,7 @@ describe("setupChannels", () => {
863912864913await runSetupChannels({} as OpenClawConfig, prompter);
865914866-expect(select).toHaveBeenCalledWith(expect.objectContaining({ message: "Select a channel" }));
915+expectCalledWithMessage(select, "Select a channel");
867916expect(multiselect).not.toHaveBeenCalled();
868917});
869918@@ -1036,12 +1085,10 @@ describe("setupChannels", () => {
10361085{ allowDisable: true },
10371086);
103810871039-expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
1040-expect.objectContaining({ channel: "external-chat" }),
1041-);
1042-expect(setAccountEnabled).toHaveBeenCalledWith(
1043-expect.objectContaining({ accountId: "work", enabled: false }),
1044-);
1088+expectCalledWithFields(vi.mocked(loadChannelSetupPluginRegistrySnapshotForChannel), {
1089+channel: "external-chat",
1090+});
1091+expectCalledWithFields(setAccountEnabled, { accountId: "work", enabled: false });
10451092expect(
10461093(
10471094next.channels?.["external-chat"] as
@@ -1067,12 +1114,8 @@ describe("setupChannels", () => {
10671114quickstartDefaults: true,
10681115});
106911161070-expect(select).toHaveBeenCalledWith(
1071-expect.objectContaining({ message: "Select channel (QuickStart)" }),
1072-);
1073-expect(select).toHaveBeenCalledWith(
1074-expect.objectContaining({ message: expect.stringContaining("already configured") }),
1075-);
1117+expectCalledWithMessage(select, "Select channel (QuickStart)");
1118+expectCalledWithMessageContaining(select, "already configured");
10761119expect(multiselect).not.toHaveBeenCalled();
10771120expect(text).not.toHaveBeenCalled();
10781121});
@@ -1100,7 +1143,7 @@ describe("setupChannels", () => {
1100114311011144await runSetupChannels(createTelegramCfg("token", false), prompter);
110211451103-expect(select).toHaveBeenCalledWith(expect.objectContaining({ message: "Select a channel" }));
1146+expectCalledWithMessage(select, "Select a channel");
11041147const channelSelectCall = select.mock.calls.find(
11051148([params]) => (params as { message?: string }).message === "Select a channel",
11061149);
@@ -1117,9 +1160,9 @@ describe("setupChannels", () => {
11171160 configureInteractive,
11181161});
111911621120-expect(configureInteractive).toHaveBeenCalledWith(
1121- expect.objectContaining({ configured: false, label: expect.any(String) }),
1122-);
1163+const configureInteractiveArg = callArgAt(configureInteractive, 0);
1164+expect(configureInteractiveArg.configured).toBe(false);
1165+expect(typeof configureInteractiveArg.label).toBe("string");
11231166expect(selection).toHaveBeenCalledWith([]);
11241167expect(onAccountId).not.toHaveBeenCalled();
11251168expect(cfg.channels?.telegram?.botToken).toBeUndefined();
@@ -1169,9 +1212,9 @@ describe("setupChannels", () => {
11691212});
1170121311711214expect(configureWhenConfigured).toHaveBeenCalledTimes(1);
1172-expect(configureWhenConfigured).toHaveBeenCalledWith(
1173- expect.objectContaining({ configured: true, label: expect.any(String) }),
1174-);
1215+const configureWhenConfiguredArg = callArgAt(configureWhenConfigured, 0);
1216+expect(configureWhenConfiguredArg.configured).toBe(true);
1217+expect(typeof configureWhenConfiguredArg.label).toBe("string");
11751218expect(configure).not.toHaveBeenCalled();
11761219expect(selection).toHaveBeenCalledWith(["telegram"]);
11771220expect(onAccountId).toHaveBeenCalledWith("telegram", "acct-2");
@@ -1186,9 +1229,9 @@ describe("setupChannels", () => {
11861229configureErrorMessage: "configure should not run when configureWhenConfigured handles skip",
11871230});
118812311189-expect(configureWhenConfigured).toHaveBeenCalledWith(
1190- expect.objectContaining({ configured: true, label: expect.any(String) }),
1191-);
1232+const configureWhenConfiguredArg = callArgAt(configureWhenConfigured, 0);
1233+expect(configureWhenConfiguredArg.configured).toBe(true);
1234+expect(typeof configureWhenConfiguredArg.label).toBe("string");
11921235expect(configure).not.toHaveBeenCalled();
11931236expect(selection).toHaveBeenCalledWith([]);
11941237expect(onAccountId).not.toHaveBeenCalled();
@@ -1218,9 +1261,9 @@ describe("setupChannels", () => {
12181261 onAccountId,
12191262});
122012631221-expect(configureInteractive).toHaveBeenCalledWith(
1222- expect.objectContaining({ configured: true, label: expect.any(String) }),
1223-);
1264+const configureInteractiveArg = callArgAt(configureInteractive, 0);
1265+expect(configureInteractiveArg.configured).toBe(true);
1266+expect(typeof configureInteractiveArg.label).toBe("string");
12241267expect(configureWhenConfigured).not.toHaveBeenCalled();
12251268expect(selection).toHaveBeenCalledWith([]);
12261269expect(onAccountId).not.toHaveBeenCalled();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。