From 0e1aa77928e5bbc386fcd44e9945a0571346b5d0 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Sat, 21 Feb 2026 17:51:56 -0500 Subject: [PATCH] chore(tsgo/format): fix CI errors --- src/auto-reply/reply/reply-flow.test.ts | 2 +- src/auto-reply/reply/session.test.ts | 2 +- src/cli/program/helpers.test.ts | 2 +- ...tion.rejects-routing-allowfrom.e2e.test.ts | 8 ++- src/config/redact-snapshot.test.ts | 8 +-- .../isolated-agent/delivery-target.test.ts | 9 +++- src/discord/monitor.test.ts | 6 +-- src/infra/exec-approvals.test.ts | 11 ++-- ...tbeat-runner.returns-default-unset.test.ts | 39 ++++++++++---- src/infra/outbound/outbound.test.ts | 14 ++--- src/memory/mmr.test.ts | 16 ++++-- src/memory/qmd-manager.test.ts | 2 +- src/telegram/format.wrap-md.test.ts | 18 ++++--- src/telegram/model-buttons.test.ts | 2 +- src/telegram/send.test.ts | 53 +++++++++++++++---- 15 files changed, 133 insertions(+), 59 deletions(-) diff --git a/src/auto-reply/reply/reply-flow.test.ts b/src/auto-reply/reply/reply-flow.test.ts index 4ee28552c..9eed58d55 100644 --- a/src/auto-reply/reply/reply-flow.test.ts +++ b/src/auto-reply/reply/reply-flow.test.ts @@ -449,7 +449,7 @@ describe("parseLineDirectives", () => { if (testCase.expectFooter) { expect(flexMessage?.contents?.footer?.contents?.length, testCase.name).toBeGreaterThan(0); } - if (testCase.expectBodyContents) { + if ("expectBodyContents" in testCase && testCase.expectBodyContents) { expect(flexMessage?.contents?.body?.contents, testCase.name).toBeDefined(); } } diff --git a/src/auto-reply/reply/session.test.ts b/src/auto-reply/reply/session.test.ts index 32b0dc893..181934f98 100644 --- a/src/auto-reply/reply/session.test.ts +++ b/src/auto-reply/reply/session.test.ts @@ -626,7 +626,7 @@ describe("initSessionState reset triggers in WhatsApp groups", () => { }); const cfg = makeCfg({ storePath, - allowFrom: testCase.allowFrom, + allowFrom: [...testCase.allowFrom], }); const result = await initSessionState({ diff --git a/src/cli/program/helpers.test.ts b/src/cli/program/helpers.test.ts index 0c475d3a6..d9c329569 100644 --- a/src/cli/program/helpers.test.ts +++ b/src/cli/program/helpers.test.ts @@ -34,7 +34,7 @@ describe("program helpers", () => { it("resolveActionArgs returns empty array for missing/invalid args", () => { const command = new Command(); - (command as Command & { args?: unknown }).args = "not-an-array"; + (command as unknown as { args?: unknown }).args = "not-an-array"; expect(resolveActionArgs(command)).toEqual([]); expect(resolveActionArgs(undefined)).toEqual([]); }); diff --git a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.e2e.test.ts b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.e2e.test.ts index 0e134188a..5ebaf353d 100644 --- a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.e2e.test.ts +++ b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.e2e.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { migrateLegacyConfig, validateConfigObject } from "./config.js"; +import type { OpenClawConfig } from "./config.js"; function getLegacyRouting(config: unknown) { return (config as { routing?: Record } | undefined)?.routing; @@ -470,13 +471,16 @@ describe("legacy config detection", () => { const res = validateConfigObject(testCase.input); expect(res.ok, testCase.name).toBe(true); if (res.ok) { - if (testCase.expectedTopLevel !== undefined) { + if ("expectedTopLevel" in testCase && testCase.expectedTopLevel !== undefined) { expect(res.config.channels?.telegram?.streaming, testCase.name).toBe( testCase.expectedTopLevel, ); expect(res.config.channels?.telegram?.streamMode, testCase.name).toBeUndefined(); } - if (testCase.expectedAccountStreaming !== undefined) { + if ( + "expectedAccountStreaming" in testCase && + testCase.expectedAccountStreaming !== undefined + ) { expect(res.config.channels?.telegram?.accounts?.ops?.streaming, testCase.name).toBe( testCase.expectedAccountStreaming, ); diff --git a/src/config/redact-snapshot.test.ts b/src/config/redact-snapshot.test.ts index a82976d0b..627fcd945 100644 --- a/src/config/redact-snapshot.test.ts +++ b/src/config/redact-snapshot.test.ts @@ -409,12 +409,12 @@ describe("redactConfigSnapshot", () => { }), assert: ({ redacted, restored }) => { const cfg = redacted as Record>; - const cfgCustom2 = cfg.custom2 as unknown[]; + const cfgCustom2 = cfg.custom2 as unknown as unknown[]; expect(cfgCustom2.length).toBeGreaterThan(0); expect((cfg.custom1.anykey as Record).mySecret).toBe(REDACTED_SENTINEL); expect((cfgCustom2[0] as Record).mySecret).toBe(REDACTED_SENTINEL); const out = restored as Record>; - const outCustom2 = out.custom2 as unknown[]; + const outCustom2 = out.custom2 as unknown as unknown[]; expect(outCustom2.length).toBeGreaterThan(0); expect((out.custom1.anykey as Record).mySecret).toBe( "this-is-a-custom-secret-value", @@ -436,12 +436,12 @@ describe("redactConfigSnapshot", () => { }), assert: ({ redacted, restored }) => { const cfg = redacted as Record>; - const cfgCustom2 = cfg.custom2 as unknown[]; + const cfgCustom2 = cfg.custom2 as unknown as unknown[]; expect(cfgCustom2.length).toBeGreaterThan(0); expect((cfg.custom1.anykey as Record).mySecret).toBe(REDACTED_SENTINEL); expect((cfgCustom2[0] as Record).mySecret).toBe(REDACTED_SENTINEL); const out = restored as Record>; - const outCustom2 = out.custom2 as unknown[]; + const outCustom2 = out.custom2 as unknown as unknown[]; expect(outCustom2.length).toBeGreaterThan(0); expect((out.custom1.anykey as Record).mySecret).toBe( "this-is-a-custom-secret-value", diff --git a/src/cron/isolated-agent/delivery-target.test.ts b/src/cron/isolated-agent/delivery-target.test.ts index 8db575058..9f58a10e6 100644 --- a/src/cron/isolated-agent/delivery-target.test.ts +++ b/src/cron/isolated-agent/delivery-target.test.ts @@ -9,7 +9,9 @@ vi.mock("../../config/sessions.js", () => ({ })); vi.mock("../../infra/outbound/channel-selection.js", () => ({ - resolveMessageChannelSelection: vi.fn().mockResolvedValue({ channel: "telegram" }), + resolveMessageChannelSelection: vi + .fn() + .mockResolvedValue({ channel: "telegram", configured: ["telegram"] }), })); vi.mock("../../pairing/pairing-store.js", () => ({ @@ -261,7 +263,10 @@ describe("resolveDeliveryTarget", () => { it("uses channel selection result when no previous session target exists", async () => { setMainSessionEntry(undefined); - vi.mocked(resolveMessageChannelSelection).mockResolvedValueOnce({ channel: "telegram" }); + vi.mocked(resolveMessageChannelSelection).mockResolvedValueOnce({ + channel: "telegram", + configured: ["telegram"], + }); const result = await resolveForAgent({ cfg: makeCfg({ bindings: [] }), diff --git a/src/discord/monitor.test.ts b/src/discord/monitor.test.ts index 2d0347a56..4333a2e6d 100644 --- a/src/discord/monitor.test.ts +++ b/src/discord/monitor.test.ts @@ -705,7 +705,7 @@ describe("discord reaction notification gating", () => { botId: "bot-1", messageAuthorId: "user-1", userId: "user-2", - allowlist: [], + allowlist: [] as string[], }, expected: false, }, @@ -717,7 +717,7 @@ describe("discord reaction notification gating", () => { messageAuthorId: "user-1", userId: "123", userName: "steipete", - allowlist: ["123", "other"], + allowlist: ["123", "other"] as string[], }, expected: true, }, @@ -984,7 +984,7 @@ describe("discord reaction notification modes", () => { { name: "allowlist mode", reactionNotifications: "allowlist" as const, - users: ["123"], + users: ["123"] as string[], userId: "123", channelType: ChannelType.GuildText, channelId: undefined, diff --git a/src/infra/exec-approvals.test.ts b/src/infra/exec-approvals.test.ts index 530562a33..e449b4ac5 100644 --- a/src/infra/exec-approvals.test.ts +++ b/src/infra/exec-approvals.test.ts @@ -24,6 +24,7 @@ import { resolveExecApprovalsSocketPath, resolveSafeBins, type ExecAllowlistEntry, + type ExecApprovalsAgent, type ExecApprovalsFile, } from "./exec-approvals.js"; import { SAFE_BIN_PROFILE_FIXTURES, SAFE_BIN_PROFILES } from "./exec-safe-bin-policy.js"; @@ -204,7 +205,7 @@ describe("exec approvals command resolution", () => { return { command: "./scripts/run.sh --flag", cwd, - envPath: undefined as string | undefined, + envPath: undefined as NodeJS.ProcessEnv | undefined, expectedPath: script, expectedExecutableName: undefined, }; @@ -222,7 +223,7 @@ describe("exec approvals command resolution", () => { return { command: '"./bin/tool" --version', cwd, - envPath: undefined as string | undefined, + envPath: undefined as NodeJS.ProcessEnv | undefined, expectedPath: script, expectedExecutableName: undefined, }; @@ -258,7 +259,7 @@ describe("exec approvals shell parsing", () => { for (const testCase of cases) { const res = analyzeShellCommand({ command: testCase.command }); expect(res.ok, testCase.name).toBe(true); - if (testCase.expectedSegments) { + if ("expectedSegments" in testCase) { expect( res.segments.map((seg) => seg.argv[0]), testCase.name, @@ -1197,7 +1198,7 @@ describe("normalizeExecApprovals handles string allowlist entries (#9790)", () = const patterns = getMainAllowlistPatterns({ version: 1, agents: { - main: { allowlist: testCase.allowlist } as ExecApprovalsFile["agents"]["main"], + main: { allowlist: testCase.allowlist } as ExecApprovalsAgent, }, }); expect(patterns, testCase.name).toEqual(testCase.expectedPatterns); @@ -1205,7 +1206,7 @@ describe("normalizeExecApprovals handles string allowlist entries (#9790)", () = const entries = normalizeExecApprovals({ version: 1, agents: { - main: { allowlist: testCase.allowlist } as ExecApprovalsFile["agents"]["main"], + main: { allowlist: testCase.allowlist } as ExecApprovalsAgent, }, }).agents?.main?.allowlist; expectNoSpreadStringArtifacts(entries ?? []); diff --git a/src/infra/heartbeat-runner.returns-default-unset.test.ts b/src/infra/heartbeat-runner.returns-default-unset.test.ts index ccdfc6285..9dd7a025b 100644 --- a/src/infra/heartbeat-runner.returns-default-unset.test.ts +++ b/src/infra/heartbeat-runner.returns-default-unset.test.ts @@ -17,6 +17,7 @@ import { buildAgentPeerSessionKey } from "../routing/session-key.js"; import { createOutboundTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js"; import { isHeartbeatEnabledForAgent, + type HeartbeatDeps, resolveHeartbeatIntervalMs, resolveHeartbeatPrompt, runHeartbeatOnce, @@ -439,7 +440,10 @@ describe("resolveHeartbeatSenderContext", () => { }); describe("runHeartbeatOnce", () => { - const createHeartbeatDeps = (sendWhatsApp: ReturnType, nowMs = 0) => ({ + const createHeartbeatDeps = ( + sendWhatsApp: NonNullable, + nowMs = 0, + ): HeartbeatDeps => ({ sendWhatsApp, getQueueSize: () => 0, nowMs: () => nowMs, @@ -516,7 +520,7 @@ describe("runHeartbeatOnce", () => { ); replySpy.mockResolvedValue([{ text: "Let me check..." }, { text: "Final alert" }]); - const sendWhatsApp = vi.fn().mockResolvedValue({ + const sendWhatsApp = vi.fn>().mockResolvedValue({ messageId: "m1", toJid: "jid", }); @@ -569,7 +573,7 @@ describe("runHeartbeatOnce", () => { }), ); replySpy.mockResolvedValue([{ text: "Final alert" }]); - const sendWhatsApp = vi.fn().mockResolvedValue({ + const sendWhatsApp = vi.fn>().mockResolvedValue({ messageId: "m1", toJid: "jid", }); @@ -645,7 +649,7 @@ describe("runHeartbeatOnce", () => { ); replySpy.mockResolvedValue([{ text: "Final alert" }]); - const sendWhatsApp = vi.fn().mockResolvedValue({ + const sendWhatsApp = vi.fn>().mockResolvedValue({ messageId: "m1", toJid: "jid", }); @@ -749,7 +753,9 @@ describe("runHeartbeatOnce", () => { replySpy.mockReset(); replySpy.mockResolvedValue([{ text: testCase.message }]); - const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "m1", toJid: "jid" }); + const sendWhatsApp = vi + .fn>() + .mockResolvedValue({ messageId: "m1", toJid: "jid" }); await runHeartbeatOnce({ cfg, @@ -811,7 +817,9 @@ describe("runHeartbeatOnce", () => { ); replySpy.mockResolvedValue([{ text: "Final alert" }]); - const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "m1", toJid: "jid" }); + const sendWhatsApp = vi + .fn>() + .mockResolvedValue({ messageId: "m1", toJid: "jid" }); await runHeartbeatOnce({ cfg, @@ -827,7 +835,12 @@ describe("runHeartbeatOnce", () => { it("handles reasoning payload delivery variants", async () => { const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cases = [ + const cases: Array<{ + name: string; + caseDir: string; + replies: Array<{ text: string }>; + expectedTexts: string[]; + }> = [ { name: "reasoning + final payload", caseDir: "hb-reasoning", @@ -840,7 +853,7 @@ describe("runHeartbeatOnce", () => { replies: [{ text: "Reasoning:\n_Because it helps_" }, { text: "HEARTBEAT_OK" }], expectedTexts: ["Reasoning:\n_Because it helps_"], }, - ] as const; + ]; for (const testCase of cases) { const tmpDir = await createCaseDir(testCase.caseDir); @@ -876,7 +889,9 @@ describe("runHeartbeatOnce", () => { replySpy.mockReset(); replySpy.mockResolvedValue(testCase.replies); - const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "m1", toJid: "jid" }); + const sendWhatsApp = vi + .fn>() + .mockResolvedValue({ messageId: "m1", toJid: "jid" }); await runHeartbeatOnce({ cfg, @@ -934,7 +949,7 @@ describe("runHeartbeatOnce", () => { ); replySpy.mockResolvedValue({ text: "Hello from heartbeat" }); - const sendWhatsApp = vi.fn().mockResolvedValue({ + const sendWhatsApp = vi.fn>().mockResolvedValue({ messageId: "m1", toJid: "jid", }); @@ -1020,7 +1035,9 @@ describe("runHeartbeatOnce", () => { const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); replySpy.mockResolvedValue({ text: params.replyText ?? "Checked logs and PRs" }); - const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "m1", toJid: "jid" }); + const sendWhatsApp = vi + .fn>() + .mockResolvedValue({ messageId: "m1", toJid: "jid" }); const res = await runHeartbeatOnce({ cfg, reason: params.reason, diff --git a/src/infra/outbound/outbound.test.ts b/src/infra/outbound/outbound.test.ts index 18394d752..3eb0fd01f 100644 --- a/src/infra/outbound/outbound.test.ts +++ b/src/infra/outbound/outbound.test.ts @@ -407,7 +407,7 @@ describe("DirectoryCache", () => { ] as const, expected: { a: "value-a2", b: undefined, c: "value-c" }, }, - ] as const; + ]; for (const testCase of cases) { const cache = new DirectoryCache(60_000, 2); @@ -477,7 +477,7 @@ describe("buildOutboundResultEnvelope", () => { input: { delivery: discordDelivery, flattenDelivery: false }, expected: { delivery: discordDelivery }, }, - ] as const; + ]; for (const testCase of cases) { expect(buildOutboundResultEnvelope(testCase.input), testCase.name).toEqual(testCase.expected); } @@ -519,7 +519,7 @@ describe("formatOutboundDeliverySummary", () => { }, expected: "✅ Sent via Discord. Message ID: d1 (channel chan)", }, - ] as const; + ]; for (const testCase of cases) { expect(formatOutboundDeliverySummary(testCase.channel, testCase.result), testCase.name).toBe( @@ -581,7 +581,7 @@ describe("buildOutboundDeliveryJson", () => { timestamp: 123, }, }, - ] as const; + ]; for (const testCase of cases) { expect(buildOutboundDeliveryJson(testCase.input), testCase.name).toEqual(testCase.expected); @@ -602,7 +602,7 @@ describe("formatGatewaySummary", () => { input: { action: "Poll sent", channel: "discord", messageId: "p1" }, expected: "✅ Poll sent via gateway (discord). Message ID: p1", }, - ] as const; + ]; for (const testCase of cases) { expect(formatGatewaySummary(testCase.input), testCase.name).toBe(testCase.expected); @@ -844,7 +844,7 @@ describe("normalizeOutboundPayloadsForJson", () => { }, ], }, - ] as const; + ]; for (const testCase of cases) { expect(normalizeOutboundPayloadsForJson(testCase.input)).toEqual(testCase.expected); @@ -879,7 +879,7 @@ describe("formatOutboundPayloadLog", () => { }, expected: "MEDIA:https://x.test/a.png", }, - ] as const; + ]; for (const testCase of cases) { expect(formatOutboundPayloadLog(testCase.input), testCase.name).toBe(testCase.expected); diff --git a/src/memory/mmr.test.ts b/src/memory/mmr.test.ts index ec9135d10..621d1e509 100644 --- a/src/memory/mmr.test.ts +++ b/src/memory/mmr.test.ts @@ -48,9 +48,19 @@ describe("jaccardSimilarity", () => { expected: 1, }, { name: "disjoint sets", left: new Set(["a", "b"]), right: new Set(["c", "d"]), expected: 0 }, - { name: "two empty sets", left: new Set(), right: new Set(), expected: 1 }, - { name: "left non-empty right empty", left: new Set(["a"]), right: new Set(), expected: 0 }, - { name: "left empty right non-empty", left: new Set(), right: new Set(["a"]), expected: 0 }, + { name: "two empty sets", left: new Set(), right: new Set(), expected: 1 }, + { + name: "left non-empty right empty", + left: new Set(["a"]), + right: new Set(), + expected: 0, + }, + { + name: "left empty right non-empty", + left: new Set(), + right: new Set(["a"]), + expected: 0, + }, { name: "partial overlap", left: new Set(["a", "b", "c"]), diff --git a/src/memory/qmd-manager.test.ts b/src/memory/qmd-manager.test.ts index 84740266b..68d6f274b 100644 --- a/src/memory/qmd-manager.test.ts +++ b/src/memory/qmd-manager.test.ts @@ -1249,7 +1249,7 @@ describe("QmdMemoryManager", () => { for (const testCase of cases) { const { manager } = await createManager(); - const restoreOpen = testCase.installOpenSpy?.(); + const restoreOpen = "installOpenSpy" in testCase ? testCase.installOpenSpy() : undefined; try { const result = await manager.readFile(testCase.request); expect(result, testCase.name).toEqual({ text: "", path: testCase.expectedPath }); diff --git a/src/telegram/format.wrap-md.test.ts b/src/telegram/format.wrap-md.test.ts index 84749d3f9..37ef4e809 100644 --- a/src/telegram/format.wrap-md.test.ts +++ b/src/telegram/format.wrap-md.test.ts @@ -237,11 +237,15 @@ describe("edge cases", () => { ] as const; for (const testCase of cases) { const result = markdownToTelegramHtml(testCase.input); - for (const expected of testCase.contains ?? []) { - expect(result, testCase.name).toContain(expected); + if ("contains" in testCase) { + for (const expected of testCase.contains) { + expect(result, testCase.name).toContain(expected); + } } - for (const unexpected of testCase.notContains ?? []) { - expect(result, testCase.name).not.toContain(unexpected); + if ("notContains" in testCase) { + for (const unexpected of testCase.notContains) { + expect(result, testCase.name).not.toContain(unexpected); + } } } }); @@ -297,8 +301,10 @@ describe("edge cases", () => { if ("expectedExact" in testCase) { expect(result, testCase.name).toBe(testCase.expectedExact); } - for (const expected of testCase.contains ?? []) { - expect(result, testCase.name).toContain(expected); + if ("contains" in testCase) { + for (const expected of testCase.contains) { + expect(result, testCase.name).toContain(expected); + } } } }); diff --git a/src/telegram/model-buttons.test.ts b/src/telegram/model-buttons.test.ts index 0ddc22909..ac3ef5d51 100644 --- a/src/telegram/model-buttons.test.ts +++ b/src/telegram/model-buttons.test.ts @@ -166,7 +166,7 @@ describe("buildModelsKeyboard", () => { for (const testCase of cases) { const result = buildModelsKeyboard({ provider: "anthropic", - models: testCase.params.models, + models: [...testCase.params.models], currentPage: testCase.params.currentPage, totalPages: 3, pageSize: 2, diff --git a/src/telegram/send.test.ts b/src/telegram/send.test.ts index 6eb8d8fee..62ec6054f 100644 --- a/src/telegram/send.test.ts +++ b/src/telegram/send.test.ts @@ -74,7 +74,11 @@ describe("sent-message-cache", () => { describe("buildInlineKeyboard", () => { it("normalizes keyboard inputs", () => { - const cases = [ + const cases: Array<{ + name: string; + input: Parameters[0]; + expected: ReturnType; + }> = [ { name: "empty input", input: undefined, @@ -141,7 +145,7 @@ describe("buildInlineKeyboard", () => { inline_keyboard: [[{ text: "Ok", callback_data: "cmd:ok" }]], }, }, - ] as const; + ]; for (const testCase of cases) { expect(buildInlineKeyboard(testCase.input), testCase.name).toEqual(testCase.expected); } @@ -539,7 +543,12 @@ describe("sendMessageTelegram", () => { it("applies reply markup and thread options to split video-note sends", async () => { const chatId = "123"; - const cases = [ + const cases: Array<{ + text: string; + options: Partial[2]>>; + expectedVideoNote: Record; + expectedMessage: Record; + }> = [ { text: "Check this out", options: { @@ -564,7 +573,7 @@ describe("sendMessageTelegram", () => { reply_to_message_id: 999, }, }, - ] as const; + ]; for (const testCase of cases) { const sendVideoNote = vi.fn().mockResolvedValue({ @@ -681,7 +690,19 @@ describe("sendMessageTelegram", () => { }); it("routes audio media to sendAudio/sendVoice based on voice compatibility", async () => { - const cases = [ + const cases: Array<{ + name: string; + chatId: string; + text: string; + mediaUrl: string; + contentType: string; + fileName: string; + asVoice?: boolean; + messageThreadId?: number; + replyToMessageId?: number; + expectedMethod: "sendAudio" | "sendVoice"; + expectedOptions: Record; + }> = [ { name: "default audio send", chatId: "123", @@ -732,7 +753,7 @@ describe("sendMessageTelegram", () => { expectedMethod: "sendVoice" as const, expectedOptions: { caption: "caption", parse_mode: "HTML" }, }, - ] as const; + ]; for (const testCase of cases) { const sendAudio = vi.fn().mockResolvedValue({ @@ -1210,12 +1231,22 @@ describe("editMessageTelegram", () => { }); it("handles button payload + parse fallback behavior", async () => { - const cases = [ + const cases: Array<{ + name: string; + setup: () => { + text: string; + buttons: Parameters[0]; + }; + expectedCalls: number; + firstExpectNoReplyMarkup?: boolean; + firstExpectReplyMarkup?: Record; + secondExpectReplyMarkup?: Record; + }> = [ { name: "buttons undefined keeps existing keyboard", setup: () => { botApi.editMessageText.mockResolvedValue({ message_id: 1, chat: { id: "123" } }); - return { text: "hi", buttons: undefined as [] | undefined }; + return { text: "hi", buttons: undefined }; }, expectedCalls: 1, firstExpectNoReplyMarkup: true, @@ -1224,7 +1255,7 @@ describe("editMessageTelegram", () => { name: "buttons empty clears keyboard", setup: () => { botApi.editMessageText.mockResolvedValue({ message_id: 1, chat: { id: "123" } }); - return { text: "hi", buttons: [] as [] }; + return { text: "hi", buttons: [] }; }, expectedCalls: 1, firstExpectReplyMarkup: { inline_keyboard: [] }, @@ -1235,13 +1266,13 @@ describe("editMessageTelegram", () => { botApi.editMessageText .mockRejectedValueOnce(new Error("400: Bad Request: can't parse entities")) .mockResolvedValueOnce({ message_id: 1, chat: { id: "123" } }); - return { text: " html", buttons: [] as [] }; + return { text: " html", buttons: [] }; }, expectedCalls: 2, firstExpectReplyMarkup: { inline_keyboard: [] }, secondExpectReplyMarkup: { inline_keyboard: [] }, }, - ] as const; + ]; for (const testCase of cases) { botApi.editMessageText.mockReset();