const { User, InboxItem } = require('../../../models'); const telegramPoller = require('../../../modules/telegram/telegramPoller'); const https = require('https'); // Mock the database models jest.mock('../../../models', () => ({ User: { update: jest.fn(), findAll: jest.fn(), findOne: jest.fn(), }, InboxItem: { create: jest.fn(), findOne: jest.fn(), }, })); // Mock https module jest.mock('https', () => ({ get: jest.fn(), request: jest.fn(), })); describe('TelegramPoller Duplicate Prevention', () => { let mockUser; beforeEach(() => { jest.clearAllMocks(); mockUser = { id: 1, telegram_bot_token: 'test-token', telegram_chat_id: '123456789', }; // Reset poller state telegramPoller.stopPolling(); }); describe('Update ID Tracking', () => { test('should filter out already processed updates', () => { const updates = [ { update_id: 100, message: { text: 'Hello 1', message_id: 1, chat: { id: 123 }, }, }, { update_id: 101, message: { text: 'Hello 2', message_id: 2, chat: { id: 123 }, }, }, { update_id: 102, message: { text: 'Hello 3', message_id: 3, chat: { id: 123 }, }, }, ]; // Test internal function for filtering const processedUpdates = new Set(['1-100', '1-101']); const newUpdates = updates.filter((update) => { const updateKey = `1-${update.update_id}`; return !processedUpdates.has(updateKey); }); expect(newUpdates).toHaveLength(1); expect(newUpdates[0].update_id).toBe(102); }); test('should track highest update ID correctly', () => { const updates = [ { update_id: 98 }, { update_id: 101 }, { update_id: 99 }, ]; const highestUpdateId = telegramPoller._getHighestUpdateId(updates); expect(highestUpdateId).toBe(101); }); test('should handle empty updates array', () => { const highestUpdateId = telegramPoller._getHighestUpdateId([]); expect(highestUpdateId).toBe(0); }); }); describe('User List Management', () => { test('should not add duplicate users', () => { const users = [{ id: 1, name: 'User 1' }]; const newUser = { id: 1, name: 'User 1 Updated' }; const userExists = telegramPoller._userExistsInList(users, 1); expect(userExists).toBe(true); const updatedUsers = telegramPoller._addUserToList(users, newUser); expect(updatedUsers).toHaveLength(1); expect(updatedUsers).toEqual(users); // Should return original array unchanged }); test('should add new users correctly', () => { const users = [{ id: 1, name: 'User 1' }]; const newUser = { id: 2, name: 'User 2' }; const userExists = telegramPoller._userExistsInList(users, 2); expect(userExists).toBe(false); const updatedUsers = telegramPoller._addUserToList(users, newUser); expect(updatedUsers).toHaveLength(2); expect(updatedUsers).toContain(newUser); }); test('should remove users correctly', () => { const users = [ { id: 1, name: 'User 1' }, { id: 2, name: 'User 2' }, { id: 3, name: 'User 3' }, ]; const updatedUsers = telegramPoller._removeUserFromList(users, 2); expect(updatedUsers).toHaveLength(2); expect(updatedUsers.find((u) => u.id === 2)).toBeUndefined(); expect(updatedUsers.find((u) => u.id === 1)).toBeDefined(); expect(updatedUsers.find((u) => u.id === 3)).toBeDefined(); }); }); describe('Message Parameters', () => { test('should create message parameters without reply', () => { const params = telegramPoller._createMessageParams( '123', 'Hello World' ); expect(params).toEqual({ chat_id: '123', text: 'Hello World', }); }); test('should create message parameters with reply', () => { const params = telegramPoller._createMessageParams( '123', 'Hello World', 456 ); expect(params).toEqual({ chat_id: '123', text: 'Hello World', reply_to_message_id: 456, }); }); }); describe('Telegram URL Creation', () => { test('should create URL without parameters', () => { const url = telegramPoller._createTelegramUrl('token123', 'getMe'); expect(url).toBe('https://api.telegram.org/bottoken123/getMe'); }); test('should create URL with parameters', () => { const url = telegramPoller._createTelegramUrl( 'token123', 'getUpdates', { offset: '100', timeout: '30', } ); expect(url).toBe( 'https://api.telegram.org/bottoken123/getUpdates?offset=100&timeout=30' ); }); }); describe('State Management', () => { test('should return correct initial state', () => { const state = telegramPoller._createPollerState(); expect(state).toEqual({ running: false, interval: null, pollInterval: 5000, usersToPool: [], userStatus: {}, processedUpdates: expect.any(Set), }); }); test('should track poller status correctly', () => { const status = telegramPoller.getStatus(); expect(status).toEqual({ running: false, usersCount: 0, pollInterval: 5000, userStatus: {}, }); }); }); }); describe('Multiple Telegram Allowed Users', () => { test('should allow multiple authorized Telegram users when telegram_allowed_users is configured', async () => { const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(); https.request.mockImplementation((url, options, callback) => { // Simulate successful response const mockResponse = { on: jest.fn((event, handler) => { if (event === 'data') handler(JSON.stringify({})); if (event === 'end') handler(); return mockResponse; }), }; callback(mockResponse); return { on: jest.fn(), write: jest.fn(), end: jest.fn(), }; }); const user = { id: 1, telegram_bot_token: 'test-token', telegram_chat_id: '111111111', telegram_allowed_users: '@bob, @alice', }; const bobUpdate = { message: { from: { id: 100, username: 'bob' }, chat: { id: 111111111 }, // telegram_chat_id text: 'Test message from Bob', message_id: 1, }, }; const aliceUpdate = { message: { from: { id: 200, username: 'alice' }, chat: { id: 222222222 }, // Different chat ID text: 'Test message from Alice', message_id: 2, }, }; await telegramPoller._processMessage(user, aliceUpdate); await telegramPoller._processMessage(user, bobUpdate); // Both should log successful processing expect(consoleLogSpy).toHaveBeenCalledWith( expect.stringContaining('Test message from Alice') ); expect(consoleLogSpy).toHaveBeenCalledWith( expect.stringContaining('Test message from Bob') ); consoleLogSpy.mockRestore(); }); });