diff --git a/src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts b/src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts index b85c8c018c0..7832f318de1 100644 --- a/src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts +++ b/src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts @@ -1,12 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; import * as ssrf from "../infra/net/ssrf.js"; +import { onSpy, sendChatActionSpy } from "./bot.media.e2e-harness.js"; -const useSpy = vi.fn(); -const middlewareUseSpy = vi.fn(); -const onSpy = vi.fn(); -const stopSpy = vi.fn(); -const sendChatActionSpy = vi.fn(); const cacheStickerSpy = vi.fn(); const getCachedStickerSpy = vi.fn(); const describeStickerImageSpy = vi.fn(); @@ -22,21 +17,8 @@ const sleep = async (ms: number) => { await new Promise((resolve) => setTimeout(resolve, ms)); }; -type ApiStub = { - config: { use: (arg: unknown) => void }; - sendChatAction: typeof sendChatActionSpy; - setMyCommands: (commands: Array<{ command: string; description: string }>) => Promise; -}; - -const apiStub: ApiStub = { - config: { use: useSpy }, - sendChatAction: sendChatActionSpy, - setMyCommands: vi.fn(async () => undefined), -}; - beforeEach(() => { vi.useRealTimers(); - resetInboundDedupe(); lookupMock.mockResolvedValue([{ address: "93.184.216.34", family: 4 }]); resolvePinnedHostnameSpy = vi .spyOn(ssrf, "resolvePinnedHostname") @@ -49,82 +31,12 @@ afterEach(() => { resolvePinnedHostnameSpy = null; }); -vi.mock("grammy", () => ({ - Bot: class { - api = apiStub; - use = middlewareUseSpy; - on = onSpy; - command = vi.fn(); - stop = stopSpy; - catch = vi.fn(); - constructor(public token: string) {} - }, - InputFile: class {}, - webhookCallback: vi.fn(), -})); - -vi.mock("@grammyjs/runner", () => ({ - sequentialize: () => vi.fn(), -})); - -const throttlerSpy = vi.fn(() => "throttler"); -vi.mock("@grammyjs/transformer-throttler", () => ({ - apiThrottler: () => throttlerSpy(), -})); - -vi.mock("../media/store.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - saveMediaBuffer: vi.fn(async (buffer: Buffer, contentType?: string) => ({ - id: "media", - path: "/tmp/telegram-media", - size: buffer.byteLength, - contentType: contentType ?? "application/octet-stream", - })), - }; -}); - -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: () => ({ - channels: { telegram: { dmPolicy: "open", allowFrom: ["*"] } }, - }), - }; -}); - -vi.mock("../config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - updateLastRoute: vi.fn(async () => undefined), - }; -}); - vi.mock("./sticker-cache.js", () => ({ cacheSticker: (...args: unknown[]) => cacheStickerSpy(...args), getCachedSticker: (...args: unknown[]) => getCachedStickerSpy(...args), describeStickerImage: (...args: unknown[]) => describeStickerImageSpy(...args), })); -vi.mock("../pairing/pairing-store.js", () => ({ - readChannelAllowFromStore: vi.fn(async () => [] as string[]), - upsertChannelPairingRequest: vi.fn(async () => ({ - code: "PAIRCODE", - created: true, - })), -})); - -vi.mock("../auto-reply/reply.js", () => { - const replySpy = vi.fn(async (_ctx, opts) => { - await opts?.onReplyStart?.(); - return undefined; - }); - return { getReplyFromConfig: replySpy, __replySpy: replySpy }; -}); - describe("telegram inbound media", () => { // Parallel vitest shards can make this suite slower than the standalone run. const INBOUND_MEDIA_TEST_TIMEOUT_MS = process.platform === "win32" ? 120_000 : 90_000; diff --git a/src/telegram/bot.media.e2e-harness.ts b/src/telegram/bot.media.e2e-harness.ts new file mode 100644 index 00000000000..ac9fcb4d8da --- /dev/null +++ b/src/telegram/bot.media.e2e-harness.ts @@ -0,0 +1,94 @@ +import { beforeEach, vi } from "vitest"; +import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; + +export const useSpy = vi.fn(); +export const middlewareUseSpy = vi.fn(); +export const onSpy = vi.fn(); +export const stopSpy = vi.fn(); +export const sendChatActionSpy = vi.fn(); + +type ApiStub = { + config: { use: (arg: unknown) => void }; + sendChatAction: typeof sendChatActionSpy; + setMyCommands: (commands: Array<{ command: string; description: string }>) => Promise; +}; + +const apiStub: ApiStub = { + config: { use: useSpy }, + sendChatAction: sendChatActionSpy, + setMyCommands: vi.fn(async () => undefined), +}; + +beforeEach(() => { + resetInboundDedupe(); +}); + +vi.mock("grammy", () => ({ + Bot: class { + api = apiStub; + use = middlewareUseSpy; + on = onSpy; + command = vi.fn(); + stop = stopSpy; + catch = vi.fn(); + constructor(public token: string) {} + }, + InputFile: class {}, + webhookCallback: vi.fn(), +})); + +vi.mock("@grammyjs/runner", () => ({ + sequentialize: () => vi.fn(), +})); + +const throttlerSpy = vi.fn(() => "throttler"); +vi.mock("@grammyjs/transformer-throttler", () => ({ + apiThrottler: () => throttlerSpy(), +})); + +vi.mock("../media/store.js", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + saveMediaBuffer: vi.fn(async (buffer: Buffer, contentType?: string) => ({ + id: "media", + path: "/tmp/telegram-media", + size: buffer.byteLength, + contentType: contentType ?? "application/octet-stream", + })), + }; +}); + +vi.mock("../config/config.js", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + loadConfig: () => ({ + channels: { telegram: { dmPolicy: "open", allowFrom: ["*"] } }, + }), + }; +}); + +vi.mock("../config/sessions.js", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + updateLastRoute: vi.fn(async () => undefined), + }; +}); + +vi.mock("../pairing/pairing-store.js", () => ({ + readChannelAllowFromStore: vi.fn(async () => [] as string[]), + upsertChannelPairingRequest: vi.fn(async () => ({ + code: "PAIRCODE", + created: true, + })), +})); + +vi.mock("../auto-reply/reply.js", () => { + const replySpy = vi.fn(async (_ctx, opts) => { + await opts?.onReplyStart?.(); + return undefined; + }); + return { getReplyFromConfig: replySpy, __replySpy: replySpy }; +}); diff --git a/src/telegram/bot.media.includes-location-text-ctx-fields-pins.e2e.test.ts b/src/telegram/bot.media.includes-location-text-ctx-fields-pins.e2e.test.ts index c4a44156b7e..6350a02311c 100644 --- a/src/telegram/bot.media.includes-location-text-ctx-fields-pins.e2e.test.ts +++ b/src/telegram/bot.media.includes-location-text-ctx-fields-pins.e2e.test.ts @@ -1,97 +1,5 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; -import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; - -const useSpy = vi.fn(); -const middlewareUseSpy = vi.fn(); -const onSpy = vi.fn(); -const stopSpy = vi.fn(); -const sendChatActionSpy = vi.fn(); - -type ApiStub = { - config: { use: (arg: unknown) => void }; - sendChatAction: typeof sendChatActionSpy; - setMyCommands: (commands: Array<{ command: string; description: string }>) => Promise; -}; - -const apiStub: ApiStub = { - config: { use: useSpy }, - sendChatAction: sendChatActionSpy, - setMyCommands: vi.fn(async () => undefined), -}; - -beforeEach(() => { - resetInboundDedupe(); -}); - -vi.mock("grammy", () => ({ - Bot: class { - api = apiStub; - use = middlewareUseSpy; - on = onSpy; - command = vi.fn(); - stop = stopSpy; - catch = vi.fn(); - constructor(public token: string) {} - }, - InputFile: class {}, - webhookCallback: vi.fn(), -})); - -vi.mock("@grammyjs/runner", () => ({ - sequentialize: () => vi.fn(), -})); - -const throttlerSpy = vi.fn(() => "throttler"); -vi.mock("@grammyjs/transformer-throttler", () => ({ - apiThrottler: () => throttlerSpy(), -})); - -vi.mock("../media/store.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - saveMediaBuffer: vi.fn(async (buffer: Buffer, contentType?: string) => ({ - id: "media", - path: "/tmp/telegram-media", - size: buffer.byteLength, - contentType: contentType ?? "application/octet-stream", - })), - }; -}); - -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: () => ({ - channels: { telegram: { dmPolicy: "open", allowFrom: ["*"] } }, - }), - }; -}); - -vi.mock("../config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - updateLastRoute: vi.fn(async () => undefined), - }; -}); - -vi.mock("../pairing/pairing-store.js", () => ({ - readChannelAllowFromStore: vi.fn(async () => [] as string[]), - upsertChannelPairingRequest: vi.fn(async () => ({ - code: "PAIRCODE", - created: true, - })), -})); - -vi.mock("../auto-reply/reply.js", () => { - const replySpy = vi.fn(async (_ctx, opts) => { - await opts?.onReplyStart?.(); - return undefined; - }); - return { getReplyFromConfig: replySpy, __replySpy: replySpy }; -}); +import { describe, expect, it, vi } from "vitest"; +import { onSpy } from "./bot.media.e2e-harness.js"; describe("telegram inbound media", () => { const _INBOUND_MEDIA_TEST_TIMEOUT_MS = process.platform === "win32" ? 30_000 : 20_000;