From 0ece07cc2019d8fc1120fcb0aec89cc32adba660 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 1 Jun 2026 08:17:33 +0100 Subject: [PATCH] fix(test): wait for telegram timer flushes Revert release-time extension lane isolation for Telegram and memory, and make Telegram timer-flush tests wait for async side effects after manually firing timers. Verification: - pnpm test:serial extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts extensions/telegram/src/bot.create-telegram-bot.media-group-skip-warning.test.ts extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts extensions/telegram/src/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts test/vitest-scoped-config.test.ts - pnpm exec oxfmt --check on touched files - git diff --check on touched files --- ...te-telegram-bot.channel-post-media.test.ts | 27 +++++++++++++------ ...egram-bot.media-group-skip-warning.test.ts | 6 ++--- ...dia-file-path-no-file-download.e2e.test.ts | 6 +++-- ...t.media.stickers-and-fragments.e2e.test.ts | 6 ++--- test/vitest-scoped-config.test.ts | 8 ------ test/vitest/vitest.extension-memory.config.ts | 1 - .../vitest.extension-telegram.config.ts | 2 -- 7 files changed, 29 insertions(+), 27 deletions(-) diff --git a/extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts b/extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts index 4c6f0c9087e..6d330db91c4 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts @@ -1,3 +1,4 @@ +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const harness = await import("./bot.create-telegram-bot.test-harness.js"); @@ -197,7 +198,7 @@ describe("createTelegramBot channel_post media", () => { expect(replySpy).not.toHaveBeenCalled(); await flushChannelPostMediaGroup(setTimeoutSpy); - expect(replySpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); const payload = replyPayload() as { Body?: string }; expect(payload.Body).toContain("album caption"); } finally { @@ -235,7 +236,7 @@ describe("createTelegramBot channel_post media", () => { expect(replySpy).not.toHaveBeenCalled(); await flushChannelPostMediaGroupForDelay(setTimeoutSpy, 75); - expect(replySpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); const payload = replyPayload() as { Body?: string }; expect(payload.Body).toContain("configured album"); } finally { @@ -282,7 +283,7 @@ describe("createTelegramBot channel_post media", () => { TELEGRAM_TEST_TIMINGS.textFragmentGapMs, ); - expect(replySpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); const payload = replyPayload() as { RawBody?: string }; expect(payload.RawBody).toContain(part1.slice(0, 32)); expect(payload.RawBody).toContain(part2.slice(0, 32)); @@ -569,7 +570,7 @@ describe("createTelegramBot channel_post media", () => { expect(replySpy).not.toHaveBeenCalled(); await flushChannelPostMediaGroup(setTimeoutSpy); - expect(replySpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); const payload = replyPayload() as { Body?: string }; expect(payload.Body).toContain("partial album"); } finally { @@ -582,11 +583,17 @@ describe("createTelegramBot channel_post media", () => { replySpy.mockReset(); setOpenChannelPostConfig(); - const fetchSpy = createImageFetchSpy(); - + const runtimeError = vi.fn(); const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout"); try { - const handler = getChannelPostHandler(); + createTelegramBot({ + token: "tok", + testTimings: TELEGRAM_TEST_TIMINGS, + runtime: { error: runtimeError } as unknown as RuntimeEnv, + }); + const handler = getOnHandler("channel_post") as ( + ctx: Record, + ) => Promise; await queueChannelPostAlbum(handler, { caption: "fatal album", mediaGroupId: "fatal-album-1", @@ -597,10 +604,14 @@ describe("createTelegramBot channel_post media", () => { expect(replySpy).not.toHaveBeenCalled(); await flushChannelPostMediaGroup(setTimeoutSpy); + await vi.waitFor(() => + expect(runtimeError).toHaveBeenCalledWith( + expect.stringContaining("media group handler failed"), + ), + ); expect(replySpy).not.toHaveBeenCalled(); } finally { setTimeoutSpy.mockRestore(); - fetchSpy.mockRestore(); } }); }); diff --git a/extensions/telegram/src/bot.create-telegram-bot.media-group-skip-warning.test.ts b/extensions/telegram/src/bot.create-telegram-bot.media-group-skip-warning.test.ts index c7ddf1cf88b..7f537067f35 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.media-group-skip-warning.test.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.media-group-skip-warning.test.ts @@ -200,7 +200,7 @@ describe("createTelegramBot media-group skip warning (#55216)", () => { expect(sendMessageSpy).not.toHaveBeenCalled(); await flushChannelPostMediaGroup(setTimeoutSpy); - expect(sendMessageSpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(sendMessageSpy).toHaveBeenCalledTimes(1)); expect(sendMessageSpy).toHaveBeenCalledWith( CHANNEL_ID, expect.stringContaining("1 of 2 images"), @@ -234,7 +234,7 @@ describe("createTelegramBot media-group skip warning (#55216)", () => { }); await flushChannelPostMediaGroup(setTimeoutSpy); - expect(sendMessageSpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(sendMessageSpy).toHaveBeenCalledTimes(1)); const warningText = String(sendMessageSpy.mock.calls[0]?.[1]); expect(warningText).toContain("0 of 2 images"); expect(warningText).toContain("2 could not be fetched and were skipped"); @@ -263,7 +263,7 @@ describe("createTelegramBot media-group skip warning (#55216)", () => { }); await flushChannelPostMediaGroup(setTimeoutSpy); - expect(sendMessageSpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(sendMessageSpy).toHaveBeenCalledTimes(1)); const warningText = String(sendMessageSpy.mock.calls[0]?.[1]); expect(warningText).toContain("1 of 3 images"); expect(warningText).toContain("2 could not be fetched and were skipped"); diff --git a/extensions/telegram/src/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts b/extensions/telegram/src/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts index e16d8b1e90d..379d553e76c 100644 --- a/extensions/telegram/src/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts +++ b/extensions/telegram/src/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts @@ -481,7 +481,9 @@ describe("telegram media groups", () => { delayMs: TELEGRAM_TEST_TIMINGS.mediaGroupFlushMs, expectedCount: scenario.expectedReplyCount, }); - expect(replySpy).toHaveBeenCalledTimes(scenario.expectedReplyCount); + await vi.waitFor(() => + expect(replySpy).toHaveBeenCalledTimes(scenario.expectedReplyCount), + ); expect(runtimeError).not.toHaveBeenCalled(); scenario.assert(replySpy); @@ -568,7 +570,7 @@ describe("telegram media groups", () => { clearTimeout(timer.handle); await timer.callback(); } - expect(replySpy).toHaveBeenCalledTimes(2); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(2)); const firstPayload = replyPayload(replySpy, 0); const secondPayload = replyPayload(replySpy, 1); expect([firstPayload.Body, secondPayload.Body]).toEqual( diff --git a/extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts b/extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts index 075dbf3677d..d5aecc62930 100644 --- a/extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts +++ b/extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts @@ -272,7 +272,7 @@ describe("telegram text fragments", () => { TELEGRAM_TEST_TIMINGS.textFragmentGapMs, ); - expect(replySpy).toHaveBeenCalledTimes(1); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); const payload = replySpy.mock.calls.at(0)?.[0] as { RawBody?: string }; expect(payload.RawBody).toContain(part1.slice(0, 32)); expect(payload.RawBody).toContain(part2.slice(0, 32)); @@ -348,9 +348,9 @@ describe("telegram text fragments", () => { TELEGRAM_TEST_TIMINGS.textFragmentGapMs, ); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1)); expect(readAllowFromStore).toHaveBeenCalledWith("telegram", process.env, "default"); expect(upsertPairingRequest).not.toHaveBeenCalled(); - expect(replySpy).toHaveBeenCalledTimes(1); expect(runtimeError).not.toHaveBeenCalled(); } finally { setTimeoutSpy.mockRestore(); @@ -430,7 +430,7 @@ describe("telegram text fragments", () => { clearTimeout(timer.handle); await timer.callback(); } - expect(replySpy).toHaveBeenCalledTimes(2); + await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(2)); const rawBodies = replySpy.mock.calls.map( (call) => (call[0] as { RawBody?: string }).RawBody, ); diff --git a/test/vitest-scoped-config.test.ts b/test/vitest-scoped-config.test.ts index 11f267b3e03..b4448315a39 100644 --- a/test/vitest-scoped-config.test.ts +++ b/test/vitest-scoped-config.test.ts @@ -495,14 +495,6 @@ describe("scoped vitest configs", () => { expectThreadedNonIsolatedRunner(defaultExtensionsConfig); }); - it("isolates the Telegram extension lane so release shards do not accumulate suite state", () => { - const testConfig = requireTestConfig(defaultExtensionTelegramConfig); - expect(testConfig.pool).toBe("threads"); - expect(testConfig.isolate).toBe(true); - expect(testConfig.runner).toBeUndefined(); - expect(testConfig.fileParallelism).toBe(false); - }); - it("serializes Slack extension files that share process globals", () => { expect(requireTestConfig(defaultExtensionSlackConfig).fileParallelism).toBe(false); }); diff --git a/test/vitest/vitest.extension-memory.config.ts b/test/vitest/vitest.extension-memory.config.ts index 8fed363dab9..594e8a046b9 100644 --- a/test/vitest/vitest.extension-memory.config.ts +++ b/test/vitest/vitest.extension-memory.config.ts @@ -17,7 +17,6 @@ export function createExtensionMemoryVitestConfig( { dir: "extensions", env, - isolate: true, name: "extension-memory", passWithNoTests: true, setupFiles: ["test/setup.extensions.ts"], diff --git a/test/vitest/vitest.extension-telegram.config.ts b/test/vitest/vitest.extension-telegram.config.ts index 8768bc32f20..20c36ca04a6 100644 --- a/test/vitest/vitest.extension-telegram.config.ts +++ b/test/vitest/vitest.extension-telegram.config.ts @@ -18,11 +18,9 @@ export function createExtensionTelegramVitestConfig( dir: "extensions", env, fileParallelism: false, - isolate: true, name: "extension-telegram", passWithNoTests: true, setupFiles: ["test/setup.extensions.ts"], - useNonIsolatedRunner: false, }, ); }