import { randomUUID } from 'node:crypto'; import { INestApplication } from '@nestjs/common'; import { NestExpressApplication } from '@nestjs/platform-express'; import { Test } from '@nestjs/testing'; import { App } from 'supertest/types'; import { AppModule } from '../../src/app.module'; import { configureApp } from '../../src/app.config'; import { THROTTLER_NAMESPACE } from '../../src/common/throttler/prisma-throttler.storage'; import { TelegramApiError } from '../../src/telegram/telegram-api-error'; import { TelegramClient } from '../../src/telegram/telegram-client'; import { TelegramModule } from '../../src/telegram/telegram.module'; export interface SentMessage { chatId: bigint; text: string; } /** * Stands in for the Bot API: no network. Every sendMessage is recorded; * `failWith` scripts the next answers (an error is thrown once per entry, * in order, for the given chat or any chat). */ export class FakeTelegramClient { readonly sent: SentMessage[] = []; private readonly failures: { chatId: bigint | null; error: Error }[] = []; isConfigured(): boolean { return true; } failWith(statusCode: number, description: string, chatId?: bigint): void { this.failures.push({ chatId: chatId ?? null, error: new TelegramApiError('sendMessage', statusCode, description, null), }); } sendMessage(chatId: bigint, text: string): Promise { const index = this.failures.findIndex( (failure) => failure.chatId === null || failure.chatId === chatId, ); if (index >= 0) { const [failure] = this.failures.splice(index, 1); return Promise.reject(failure.error); } this.sent.push({ chatId, text }); return Promise.resolve(); } sentTo(chatId: bigint): SentMessage[] { return this.sent.filter((message) => message.chatId === chatId); } } export interface TelegramTestApp { app: INestApplication; telegram: FakeTelegramClient; } /** * The whole API plus TelegramModule, with the Bot API client replaced by a * FakeTelegramClient. The TelegramSender is taken from the app and driven * by the test (no worker loop runs). */ export async function createTelegramTestApp(): Promise { const telegram = new FakeTelegramClient(); const moduleFixture = await Test.createTestingModule({ imports: [AppModule, TelegramModule], }) .overrideProvider(THROTTLER_NAMESPACE) .useValue(randomUUID()) .overrideProvider(TelegramClient) .useValue(telegram) .compile(); const app = moduleFixture.createNestApplication(); configureApp(app); await app.init(); return { app, telegram }; }