2026-05-18 07:27:06 +07:00
|
|
|
// @ts-nocheck
|
2026-05-18 07:29:01 +07:00
|
|
|
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test';
|
2026-05-18 08:54:24 +07:00
|
|
|
import { config } from '../src/env';
|
2026-05-18 08:55:22 +07:00
|
|
|
import logger from '../src/utils/logger';
|
2026-05-18 07:06:21 +07:00
|
|
|
|
|
|
|
|
// Mock Telegraf and fetch
|
2026-05-18 07:29:01 +07:00
|
|
|
mock.module('telegraf', () => {
|
2026-05-18 07:06:21 +07:00
|
|
|
return {
|
|
|
|
|
Telegraf: class {
|
|
|
|
|
constructor(token) {
|
|
|
|
|
this.token = token;
|
2026-05-18 07:27:06 +07:00
|
|
|
this.telegram = {
|
2026-05-18 07:29:01 +07:00
|
|
|
sendPhoto: mock(() =>
|
|
|
|
|
Promise.resolve({
|
|
|
|
|
message_id: 12345,
|
|
|
|
|
photo: [
|
|
|
|
|
{ file_id: 'photo_id_low', file_unique_id: 'unique_id_low' },
|
|
|
|
|
{ file_id: 'photo_id_high', file_unique_id: 'unique_id_high' },
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
),
|
2026-05-18 08:18:55 +07:00
|
|
|
sendDocument: mock(() =>
|
|
|
|
|
Promise.resolve({
|
|
|
|
|
message_id: 54321,
|
|
|
|
|
document: {
|
|
|
|
|
file_id: 'document_id',
|
|
|
|
|
file_unique_id: 'document_unique_id',
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
),
|
2026-05-18 07:06:21 +07:00
|
|
|
};
|
|
|
|
|
}
|
2026-05-18 07:29:01 +07:00
|
|
|
},
|
2026-05-18 07:06:21 +07:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
const infoSpy = spyOn(logger, 'info');
|
|
|
|
|
const errorSpy = spyOn(logger, 'error');
|
2026-05-18 07:06:21 +07:00
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
describe('Telegram API Utilities', () => {
|
|
|
|
|
let forwardToStorage: any, getFileInfo: any, getBot: any;
|
2026-05-18 07:06:21 +07:00
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
infoSpy.mockClear();
|
|
|
|
|
errorSpy.mockClear();
|
|
|
|
|
global.fetch = mock(() => Promise.resolve(new Response(JSON.stringify({ ok: true }))));
|
|
|
|
|
|
|
|
|
|
// Import dynamically so mocking is applied first
|
2026-05-18 07:29:01 +07:00
|
|
|
const telegramUtils = await import('../src/utils/telegram');
|
2026-05-18 07:06:21 +07:00
|
|
|
forwardToStorage = telegramUtils.forwardToStorage;
|
|
|
|
|
getFileInfo = telegramUtils.getFileInfo;
|
|
|
|
|
getBot = telegramUtils.getBot;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
delete global.fetch;
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
describe('getBot', () => {
|
|
|
|
|
it('should return the telegraf bot instance', () => {
|
2026-05-18 07:06:21 +07:00
|
|
|
const bot = getBot();
|
|
|
|
|
expect(bot).toBeDefined();
|
2026-05-18 07:27:06 +07:00
|
|
|
expect(bot.telegram).toBeDefined();
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
describe('forwardToStorage', () => {
|
|
|
|
|
it('should forward photo to storage chat and return file details', async () => {
|
|
|
|
|
const chunk = Buffer.from('fake photo data');
|
|
|
|
|
const fileName = 'test_photo.jpg';
|
2026-05-18 19:52:46 +07:00
|
|
|
const result = await forwardToStorage(chunk, fileName, 'photo');
|
2026-05-18 07:06:21 +07:00
|
|
|
|
|
|
|
|
expect(result).toEqual({
|
2026-05-18 07:29:01 +07:00
|
|
|
telegramFileId: 'photo_id_high',
|
|
|
|
|
telegramFileUniqueId: 'unique_id_high',
|
|
|
|
|
storageMessageId: 12345,
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
2026-05-18 07:29:01 +07:00
|
|
|
expect(infoSpy).toHaveBeenCalledWith('File forwarded to storage', {
|
2026-05-18 07:06:21 +07:00
|
|
|
fileName,
|
2026-05-18 07:29:01 +07:00
|
|
|
message: 12345,
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 08:18:55 +07:00
|
|
|
it('should forward documents with source and filename payload', async () => {
|
|
|
|
|
const bot = getBot();
|
|
|
|
|
const chunk = Buffer.from('fake document data');
|
|
|
|
|
const fileName = 'document.pdf';
|
|
|
|
|
|
2026-05-18 19:52:46 +07:00
|
|
|
const result = await forwardToStorage(chunk, fileName, 'document');
|
2026-05-18 08:18:55 +07:00
|
|
|
|
|
|
|
|
expect(bot.telegram.sendDocument).toHaveBeenCalledWith(
|
2026-05-18 08:54:24 +07:00
|
|
|
config.storageChatId,
|
2026-05-18 08:18:55 +07:00
|
|
|
{ source: chunk, filename: fileName },
|
|
|
|
|
{ caption: `📁 ${fileName}` },
|
|
|
|
|
);
|
|
|
|
|
expect(result).toEqual({
|
|
|
|
|
telegramFileId: 'document_id',
|
|
|
|
|
telegramFileUniqueId: 'document_unique_id',
|
|
|
|
|
storageMessageId: 54321,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
it('should handle error when forwarding fails', async () => {
|
2026-05-18 07:06:21 +07:00
|
|
|
const bot = getBot();
|
2026-05-18 07:29:01 +07:00
|
|
|
bot.telegram.sendPhoto = mock(() => Promise.reject(new Error('Telegram send failed')));
|
2026-05-18 07:06:21 +07:00
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
const chunk = Buffer.from('fake photo data');
|
|
|
|
|
const fileName = 'test_photo.jpg';
|
2026-05-18 07:06:21 +07:00
|
|
|
|
2026-05-18 19:52:46 +07:00
|
|
|
await expect(forwardToStorage(chunk, fileName, 'photo')).rejects.toThrow(
|
2026-05-18 07:29:01 +07:00
|
|
|
'Telegram send failed',
|
|
|
|
|
);
|
|
|
|
|
expect(errorSpy).toHaveBeenCalledWith('Failed to forward file to storage', {
|
2026-05-18 07:06:21 +07:00
|
|
|
fileName,
|
2026-05-18 07:29:01 +07:00
|
|
|
error: 'Telegram send failed',
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
describe('getFileInfo', () => {
|
|
|
|
|
it('should fetch file details successfully', async () => {
|
|
|
|
|
global.fetch = mock((url, _init) => {
|
|
|
|
|
if (url.endsWith('getFile')) {
|
|
|
|
|
return Promise.resolve(
|
|
|
|
|
new Response(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
ok: true,
|
|
|
|
|
result: { file_id: 'some_file_id' },
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
} else if (url.endsWith('getInfo')) {
|
|
|
|
|
return Promise.resolve(
|
|
|
|
|
new Response(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
ok: true,
|
|
|
|
|
result: {
|
|
|
|
|
file_size: 98765,
|
|
|
|
|
mime_type: 'image/jpeg',
|
|
|
|
|
file_path: 'photos/file_0.jpg',
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
2026-05-18 07:06:21 +07:00
|
|
|
}
|
2026-05-18 07:29:01 +07:00
|
|
|
return Promise.reject(new Error('Unknown URL'));
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
const result = await getFileInfo('some_file_id', 'some_unique_id');
|
2026-05-18 07:06:21 +07:00
|
|
|
|
|
|
|
|
expect(result).toEqual({
|
|
|
|
|
file_size: 98765,
|
2026-05-18 07:29:01 +07:00
|
|
|
mime_type: 'image/jpeg',
|
|
|
|
|
file_path: 'photos/file_0.jpg',
|
2026-05-18 07:06:21 +07:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
it('should handle error when getFile fails', async () => {
|
|
|
|
|
global.fetch = mock(() =>
|
|
|
|
|
Promise.resolve(
|
|
|
|
|
new Response(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
ok: false,
|
|
|
|
|
description: 'Bad Request: file_id invalid',
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
2026-05-18 07:06:21 +07:00
|
|
|
|
2026-05-18 07:29:01 +07:00
|
|
|
await expect(getFileInfo('invalid_file_id', 'invalid_unique_id')).rejects.toThrow(
|
|
|
|
|
'Bad Request: file_id invalid',
|
|
|
|
|
);
|
2026-05-18 07:06:21 +07:00
|
|
|
expect(errorSpy).toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|