diff --git a/tests/unit/services/group-sync.test.ts b/tests/unit/services/group-sync.test.ts new file mode 100644 index 0000000..ad145eb --- /dev/null +++ b/tests/unit/services/group-sync.test.ts @@ -0,0 +1,92 @@ +import { describe, it, expect, beforeEach, mock, spyOn } from 'bun:test'; +import { GroupSyncService } from '../../src/services/group-sync'; +import { db } from '../../src/db'; +import { env } from '../../src/env'; + +// Mock the environment variables +const originalEnv = { ...env }; +const mockEnv = { + WHATSAPP_COMMUNITY_ID: 'test-community', + EVOLUTION_API_URL: 'http://test-api', + EVOLUTION_API_INSTANCE: 'test-instance', + EVOLUTION_API_KEY: 'test-key' +}; + +// Mock fetch +const mockFetch = mock.global('fetch', () => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve([ + { id: 'group1', subject: 'Group 1', linkedParent: 'test-community' }, + { id: 'group2', subject: 'Group 2', linkedParent: 'other-community' }, + { id: 'group3', subject: 'Group 3' } // No linkedParent + ]) + }); +}); + +describe('GroupSyncService', () => { + beforeEach(() => { + db.exec('DELETE FROM groups'); + GroupSyncService['lastSyncAttempt'] = 0; + Object.assign(env, mockEnv); + }); + + afterAll(() => { + Object.assign(env, originalEnv); + }); + + describe('syncGroups', () => { + it('should skip sync if called too soon', async () => { + GroupSyncService['lastSyncAttempt'] = Date.now() - 1000; + const result = await GroupSyncService.syncGroups(); + expect(result).toEqual({ added: 0, updated: 0 }); + expect(mockFetch).not.toHaveBeenCalled(); + }); + + it('should throw if WHATSAPP_COMMUNITY_ID is missing', async () => { + env.WHATSAPP_COMMUNITY_ID = ''; + await expect(GroupSyncService.syncGroups()).rejects.toThrow('WHATSAPP_COMMUNITY_ID is not set'); + }); + + it('should filter groups by community ID', async () => { + const result = await GroupSyncService.syncGroups(); + expect(result.added).toBe(1); + expect(result.updated).toBe(0); + + const groups = db.query('SELECT * FROM groups').all(); + expect(groups).toHaveLength(1); + expect(groups[0].id).toBe('group1'); + }); + + it('should update existing groups', async () => { + // Add initial group + db.exec( + "INSERT INTO groups (id, community_id, name, active) VALUES ('group1', 'test-community', 'Old Name', TRUE)" + ); + + const result = await GroupSyncService.syncGroups(); + expect(result.added).toBe(0); + expect(result.updated).toBe(1); + + const group = db.query('SELECT * FROM groups WHERE id = ?').get('group1'); + expect(group.name).toBe('Group 1'); + expect(group.active).toBe(1); + }); + + it('should mark non-matching groups as inactive', async () => { + // Add initial group not in current sync + db.exec( + "INSERT INTO groups (id, community_id, name, active) VALUES ('old-group', 'test-community', 'Old Group', TRUE)" + ); + + await GroupSyncService.syncGroups(); + const group = db.query('SELECT active FROM groups WHERE id = ?').get('old-group'); + expect(group.active).toBe(0); + }); + + it('should handle API errors', async () => { + mockFetch.mockImplementationOnce(() => Promise.resolve({ ok: false, statusText: 'Not Found' })); + await expect(GroupSyncService.syncGroups()).rejects.toThrow('API request failed: Not Found'); + }); + }); +});