refactor(tests): dedupe browser and telegram tool test fixtures

This commit is contained in:
Peter Steinberger
2026-03-03 01:22:40 +00:00
parent a3b674cc98
commit c1b37f29f0
2 changed files with 112 additions and 122 deletions

View File

@@ -108,16 +108,33 @@ function mockSingleBrowserProxyNode() {
]); ]);
} }
describe("browser tool snapshot maxChars", () => { function resetBrowserToolMocks() {
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
}
function registerBrowserToolAfterEachReset() {
afterEach(() => { afterEach(() => {
vi.clearAllMocks(); resetBrowserToolMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
}); });
}
async function runSnapshotToolCall(params: {
snapshotFormat: "ai" | "aria";
refs?: "aria" | "dom";
maxChars?: number;
profile?: string;
}) {
const tool = createBrowserTool();
await tool.execute?.("call-1", { action: "snapshot", ...params });
}
describe("browser tool snapshot maxChars", () => {
registerBrowserToolAfterEachReset();
it("applies the default ai snapshot limit", async () => { it("applies the default ai snapshot limit", async () => {
const tool = createBrowserTool(); await runSnapshotToolCall({ snapshotFormat: "ai" });
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "ai" });
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith( expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
undefined, undefined,
@@ -184,8 +201,7 @@ describe("browser tool snapshot maxChars", () => {
configMocks.loadConfig.mockReturnValue({ configMocks.loadConfig.mockReturnValue({
browser: { snapshotDefaults: { mode: "efficient" } }, browser: { snapshotDefaults: { mode: "efficient" } },
}); });
const tool = createBrowserTool(); await runSnapshotToolCall({ snapshotFormat: "ai" });
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "ai" });
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith( expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
undefined, undefined,
@@ -263,11 +279,7 @@ describe("browser tool snapshot maxChars", () => {
}); });
describe("browser tool url alias support", () => { describe("browser tool url alias support", () => {
afterEach(() => { registerBrowserToolAfterEachReset();
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
});
it("accepts url alias for open", async () => { it("accepts url alias for open", async () => {
const tool = createBrowserTool(); const tool = createBrowserTool();
@@ -308,11 +320,7 @@ describe("browser tool url alias support", () => {
}); });
describe("browser tool act compatibility", () => { describe("browser tool act compatibility", () => {
afterEach(() => { registerBrowserToolAfterEachReset();
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
});
it("accepts flattened act params for backward compatibility", async () => { it("accepts flattened act params for backward compatibility", async () => {
const tool = createBrowserTool(); const tool = createBrowserTool();
@@ -364,10 +372,7 @@ describe("browser tool act compatibility", () => {
}); });
describe("browser tool snapshot labels", () => { describe("browser tool snapshot labels", () => {
afterEach(() => { registerBrowserToolAfterEachReset();
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
});
it("returns image + text when labels are requested", async () => { it("returns image + text when labels are requested", async () => {
const tool = createBrowserTool(); const tool = createBrowserTool();
@@ -409,11 +414,7 @@ describe("browser tool snapshot labels", () => {
}); });
describe("browser tool external content wrapping", () => { describe("browser tool external content wrapping", () => {
afterEach(() => { registerBrowserToolAfterEachReset();
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
});
it("wraps aria snapshots as external content", async () => { it("wraps aria snapshots as external content", async () => {
browserClientMocks.browserSnapshot.mockResolvedValueOnce({ browserClientMocks.browserSnapshot.mockResolvedValueOnce({
@@ -525,11 +526,7 @@ describe("browser tool external content wrapping", () => {
}); });
describe("browser tool act stale target recovery", () => { describe("browser tool act stale target recovery", () => {
afterEach(() => { registerBrowserToolAfterEachReset();
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
nodesUtilsMocks.listNodes.mockResolvedValue([]);
});
it("retries chrome act once without targetId when tab id is stale", async () => { it("retries chrome act once without targetId when tab id is stale", async () => {
browserActionsMocks.browserAct browserActionsMocks.browserAct

View File

@@ -51,6 +51,22 @@ describe("handleTelegramAction", () => {
} as OpenClawConfig; } as OpenClawConfig;
} }
async function sendInlineButtonsMessage(params: {
to: string;
buttons: Array<Array<{ text: string; callback_data: string; style?: string }>>;
inlineButtons: "dm" | "group" | "all";
}) {
await handleTelegramAction(
{
action: "sendMessage",
to: params.to,
content: "Choose",
buttons: params.buttons,
},
telegramConfig({ capabilities: { inlineButtons: params.inlineButtons } }),
);
}
async function expectReactionAdded(reactionLevel: "minimal" | "extensive") { async function expectReactionAdded(reactionLevel: "minimal" | "extensive") {
await handleTelegramAction(defaultReactionAction, reactionConfig(reactionLevel)); await handleTelegramAction(defaultReactionAction, reactionConfig(reactionLevel));
expect(reactMessageTelegram).toHaveBeenCalledWith( expect(reactMessageTelegram).toHaveBeenCalledWith(
@@ -103,9 +119,6 @@ describe("handleTelegramAction", () => {
}); });
it("accepts snake_case message_id for reactions", async () => { it("accepts snake_case message_id for reactions", async () => {
const cfg = {
channels: { telegram: { botToken: "tok", reactionLevel: "minimal" } },
} as OpenClawConfig;
await handleTelegramAction( await handleTelegramAction(
{ {
action: "react", action: "react",
@@ -113,7 +126,7 @@ describe("handleTelegramAction", () => {
message_id: "456", message_id: "456",
emoji: "✅", emoji: "✅",
}, },
cfg, reactionConfig("minimal"),
); );
expect(reactMessageTelegram).toHaveBeenCalledWith( expect(reactMessageTelegram).toHaveBeenCalledWith(
"123", "123",
@@ -143,9 +156,6 @@ describe("handleTelegramAction", () => {
}); });
it("removes reactions on empty emoji", async () => { it("removes reactions on empty emoji", async () => {
const cfg = {
channels: { telegram: { botToken: "tok", reactionLevel: "minimal" } },
} as OpenClawConfig;
await handleTelegramAction( await handleTelegramAction(
{ {
action: "react", action: "react",
@@ -153,7 +163,7 @@ describe("handleTelegramAction", () => {
messageId: "456", messageId: "456",
emoji: "", emoji: "",
}, },
cfg, reactionConfig("minimal"),
); );
expect(reactMessageTelegram).toHaveBeenCalledWith( expect(reactMessageTelegram).toHaveBeenCalledWith(
"123", "123",
@@ -476,44 +486,29 @@ describe("handleTelegramAction", () => {
}); });
it("allows inline buttons in DMs with tg: prefixed targets", async () => { it("allows inline buttons in DMs with tg: prefixed targets", async () => {
const cfg = telegramConfig({ capabilities: { inlineButtons: "dm" } }); await sendInlineButtonsMessage({
await handleTelegramAction( to: "tg:5232990709",
{ buttons: [[{ text: "Ok", callback_data: "cmd:ok" }]],
action: "sendMessage", inlineButtons: "dm",
to: "tg:5232990709", });
content: "Choose",
buttons: [[{ text: "Ok", callback_data: "cmd:ok" }]],
},
cfg,
);
expect(sendMessageTelegram).toHaveBeenCalled(); expect(sendMessageTelegram).toHaveBeenCalled();
}); });
it("allows inline buttons in groups with topic targets", async () => { it("allows inline buttons in groups with topic targets", async () => {
const cfg = telegramConfig({ capabilities: { inlineButtons: "group" } }); await sendInlineButtonsMessage({
await handleTelegramAction( to: "telegram:group:-1001234567890:topic:456",
{ buttons: [[{ text: "Ok", callback_data: "cmd:ok" }]],
action: "sendMessage", inlineButtons: "group",
to: "telegram:group:-1001234567890:topic:456", });
content: "Choose",
buttons: [[{ text: "Ok", callback_data: "cmd:ok" }]],
},
cfg,
);
expect(sendMessageTelegram).toHaveBeenCalled(); expect(sendMessageTelegram).toHaveBeenCalled();
}); });
it("sends messages with inline keyboard buttons when enabled", async () => { it("sends messages with inline keyboard buttons when enabled", async () => {
const cfg = telegramConfig({ capabilities: { inlineButtons: "all" } }); await sendInlineButtonsMessage({
await handleTelegramAction( to: "@testchannel",
{ buttons: [[{ text: " Option A ", callback_data: " cmd:a " }]],
action: "sendMessage", inlineButtons: "all",
to: "@testchannel", });
content: "Choose",
buttons: [[{ text: " Option A ", callback_data: " cmd:a " }]],
},
cfg,
);
expect(sendMessageTelegram).toHaveBeenCalledWith( expect(sendMessageTelegram).toHaveBeenCalledWith(
"@testchannel", "@testchannel",
"Choose", "Choose",
@@ -524,24 +519,19 @@ describe("handleTelegramAction", () => {
}); });
it("forwards optional button style", async () => { it("forwards optional button style", async () => {
const cfg = telegramConfig({ capabilities: { inlineButtons: "all" } }); await sendInlineButtonsMessage({
await handleTelegramAction( to: "@testchannel",
{ inlineButtons: "all",
action: "sendMessage", buttons: [
to: "@testchannel", [
content: "Choose", {
buttons: [ text: "Option A",
[ callback_data: "cmd:a",
{ style: "primary",
text: "Option A", },
callback_data: "cmd:a",
style: "primary",
},
],
], ],
}, ],
cfg, });
);
expect(sendMessageTelegram).toHaveBeenCalledWith( expect(sendMessageTelegram).toHaveBeenCalledWith(
"@testchannel", "@testchannel",
"Choose", "Choose",
@@ -601,6 +591,25 @@ describe("readTelegramButtons", () => {
}); });
describe("handleTelegramAction per-account gating", () => { describe("handleTelegramAction per-account gating", () => {
function accountTelegramConfig(params: {
accounts: Record<
string,
{ botToken: string; actions?: { sticker?: boolean; reactions?: boolean } }
>;
topLevelBotToken?: string;
topLevelActions?: { reactions?: boolean };
}): OpenClawConfig {
return {
channels: {
telegram: {
...(params.topLevelBotToken ? { botToken: params.topLevelBotToken } : {}),
...(params.topLevelActions ? { actions: params.topLevelActions } : {}),
accounts: params.accounts,
},
},
} as OpenClawConfig;
}
async function expectAccountStickerSend(cfg: OpenClawConfig, accountId = "media") { async function expectAccountStickerSend(cfg: OpenClawConfig, accountId = "media") {
await handleTelegramAction( await handleTelegramAction(
{ action: "sendSticker", to: "123", fileId: "sticker-id", accountId }, { action: "sendSticker", to: "123", fileId: "sticker-id", accountId },
@@ -614,15 +623,11 @@ describe("handleTelegramAction per-account gating", () => {
} }
it("allows sticker when account config enables it", async () => { it("allows sticker when account config enables it", async () => {
const cfg = { const cfg = accountTelegramConfig({
channels: { accounts: {
telegram: { media: { botToken: "tok-media", actions: { sticker: true } },
accounts: {
media: { botToken: "tok-media", actions: { sticker: true } },
},
},
}, },
} as OpenClawConfig; });
await expectAccountStickerSend(cfg); await expectAccountStickerSend(cfg);
}); });
@@ -647,30 +652,22 @@ describe("handleTelegramAction per-account gating", () => {
it("uses account-merged config, not top-level config", async () => { it("uses account-merged config, not top-level config", async () => {
// Top-level has no sticker enabled, but the account does // Top-level has no sticker enabled, but the account does
const cfg = { const cfg = accountTelegramConfig({
channels: { topLevelBotToken: "tok-base",
telegram: { accounts: {
botToken: "tok-base", media: { botToken: "tok-media", actions: { sticker: true } },
accounts: {
media: { botToken: "tok-media", actions: { sticker: true } },
},
},
}, },
} as OpenClawConfig; });
await expectAccountStickerSend(cfg); await expectAccountStickerSend(cfg);
}); });
it("inherits top-level reaction gate when account overrides sticker only", async () => { it("inherits top-level reaction gate when account overrides sticker only", async () => {
const cfg = { const cfg = accountTelegramConfig({
channels: { topLevelActions: { reactions: false },
telegram: { accounts: {
actions: { reactions: false }, media: { botToken: "tok-media", actions: { sticker: true } },
accounts: {
media: { botToken: "tok-media", actions: { sticker: true } },
},
},
}, },
} as OpenClawConfig; });
const result = await handleTelegramAction( const result = await handleTelegramAction(
{ {
@@ -689,16 +686,12 @@ describe("handleTelegramAction per-account gating", () => {
}); });
it("allows account to explicitly re-enable top-level disabled reaction gate", async () => { it("allows account to explicitly re-enable top-level disabled reaction gate", async () => {
const cfg = { const cfg = accountTelegramConfig({
channels: { topLevelActions: { reactions: false },
telegram: { accounts: {
actions: { reactions: false }, media: { botToken: "tok-media", actions: { sticker: true, reactions: true } },
accounts: {
media: { botToken: "tok-media", actions: { sticker: true, reactions: true } },
},
},
}, },
} as OpenClawConfig; });
await handleTelegramAction( await handleTelegramAction(
{ {