import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock apiClient vi.mock('../client', () => ({ default: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), delete: vi.fn(), }, })); import { getPlatformEmailAddresses, getPlatformEmailAddress, createPlatformEmailAddress, updatePlatformEmailAddress, deletePlatformEmailAddress, removeLocalPlatformEmailAddress, syncPlatformEmailAddress, testImapConnection, testSmtpConnection, setAsDefault, testMailServerConnection, getMailServerAccounts, getAvailableDomains, getAssignableUsers, importFromMailServer, type PlatformEmailAddress, type PlatformEmailAddressListItem, type PlatformEmailAddressCreate, type PlatformEmailAddressUpdate, type AssignedUser, type AssignableUser, type EmailDomain, type TestConnectionResponse, type SyncResponse, type MailServerAccountsResponse, type ImportFromMailServerResponse, } from '../platformEmailAddresses'; import apiClient from '../client'; describe('platformEmailAddresses API', () => { beforeEach(() => { vi.clearAllMocks(); }); // ============================================================================ // List and Retrieve // ============================================================================ describe('getPlatformEmailAddresses', () => { it('fetches all platform email addresses from API', async () => { const mockAddresses: PlatformEmailAddressListItem[] = [ { id: 1, display_name: 'Support Team', sender_name: 'Support', effective_sender_name: 'Support', local_part: 'support', domain: 'talova.net', email_address: 'support@talova.net', color: '#3B82F6', assigned_user: { id: 10, email: 'john@example.com', first_name: 'John', last_name: 'Doe', full_name: 'John Doe', }, is_active: true, is_default: true, mail_server_synced: true, last_check_at: '2025-01-15T10:00:00Z', emails_processed_count: 150, created_at: '2025-01-01T00:00:00Z', updated_at: '2025-01-15T00:00:00Z', }, { id: 2, display_name: 'Sales Team', sender_name: 'Sales', effective_sender_name: 'Sales', local_part: 'sales', domain: 'talova.net', email_address: 'sales@talova.net', color: '#10B981', assigned_user: null, is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-10T00:00:00Z', }, ]; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddresses }); const result = await getPlatformEmailAddresses(); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/'); expect(result).toEqual(mockAddresses); expect(result).toHaveLength(2); expect(result[0].is_default).toBe(true); expect(result[0].assigned_user?.full_name).toBe('John Doe'); expect(result[1].assigned_user).toBeNull(); }); it('returns empty array when no email addresses exist', async () => { vi.mocked(apiClient.get).mockResolvedValue({ data: [] }); const result = await getPlatformEmailAddresses(); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/'); expect(result).toEqual([]); expect(result).toHaveLength(0); }); it('handles email addresses with no assigned users', async () => { const mockAddresses: PlatformEmailAddressListItem[] = [ { id: 1, display_name: 'Unassigned', sender_name: '', effective_sender_name: 'Unassigned', local_part: 'info', domain: 'talova.net', email_address: 'info@talova.net', color: '#6B7280', assigned_user: null, is_active: false, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-01T00:00:00Z', updated_at: '2025-01-01T00:00:00Z', }, ]; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddresses }); const result = await getPlatformEmailAddresses(); expect(result[0].assigned_user).toBeNull(); expect(result[0].is_active).toBe(false); }); }); describe('getPlatformEmailAddress', () => { it('fetches a specific platform email address by ID', async () => { const mockAddress: PlatformEmailAddress = { id: 1, display_name: 'Support Team', sender_name: 'Support', effective_sender_name: 'Support', local_part: 'support', domain: 'talova.net', email_address: 'support@talova.net', color: '#3B82F6', is_active: true, is_default: true, mail_server_synced: true, last_sync_error: undefined, last_synced_at: '2025-01-15T09:00:00Z', last_check_at: '2025-01-15T10:00:00Z', emails_processed_count: 150, created_at: '2025-01-01T00:00:00Z', updated_at: '2025-01-15T00:00:00Z', imap_settings: { host: 'mail.talova.net', port: 993, use_ssl: true, username: 'support@talova.net', folder: 'INBOX', }, smtp_settings: { host: 'mail.talova.net', port: 587, use_tls: true, use_ssl: false, username: 'support@talova.net', }, }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddress }); const result = await getPlatformEmailAddress(1); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/1/'); expect(result).toEqual(mockAddress); expect(result.imap_settings?.host).toBe('mail.talova.net'); expect(result.smtp_settings?.port).toBe(587); }); it('fetches email address without IMAP/SMTP settings', async () => { const mockAddress: PlatformEmailAddress = { id: 2, display_name: 'Info', sender_name: '', effective_sender_name: 'Info', local_part: 'info', domain: 'talova.net', email_address: 'info@talova.net', color: '#6B7280', is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-10T00:00:00Z', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddress }); const result = await getPlatformEmailAddress(2); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/2/'); expect(result.imap_settings).toBeUndefined(); expect(result.smtp_settings).toBeUndefined(); }); it('fetches email address with sync error', async () => { const mockAddress: PlatformEmailAddress = { id: 3, display_name: 'Failed Sync', sender_name: '', effective_sender_name: 'Failed Sync', local_part: 'test', domain: 'talova.net', email_address: 'test@talova.net', color: '#EF4444', is_active: true, is_default: false, mail_server_synced: false, last_sync_error: 'Connection timeout', last_synced_at: '2025-01-14T12:00:00Z', emails_processed_count: 0, created_at: '2025-01-14T00:00:00Z', updated_at: '2025-01-14T12:00:00Z', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddress }); const result = await getPlatformEmailAddress(3); expect(result.last_sync_error).toBe('Connection timeout'); expect(result.mail_server_synced).toBe(false); }); it('handles different email address IDs correctly', async () => { const mockAddress: PlatformEmailAddress = { id: 999, display_name: 'Test', sender_name: '', effective_sender_name: 'Test', local_part: 'test', domain: 'example.com', email_address: 'test@example.com', color: '#000000', is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-01T00:00:00Z', updated_at: '2025-01-01T00:00:00Z', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockAddress }); await getPlatformEmailAddress(999); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/999/'); }); }); // ============================================================================ // Create and Update // ============================================================================ describe('createPlatformEmailAddress', () => { it('creates a new platform email address with all fields', async () => { const createData: PlatformEmailAddressCreate = { display_name: 'New Support', sender_name: 'Support Team', assigned_user_id: 10, local_part: 'support', domain: 'talova.net', color: '#3B82F6', password: 'secure-password-123', is_active: true, is_default: false, }; const mockResponse: PlatformEmailAddress = { id: 5, display_name: 'New Support', sender_name: 'Support Team', effective_sender_name: 'Support Team', local_part: 'support', domain: 'talova.net', email_address: 'support@talova.net', color: '#3B82F6', is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-15T14:00:00Z', updated_at: '2025-01-15T14:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await createPlatformEmailAddress(createData); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/', createData); expect(result).toEqual(mockResponse); expect(result.id).toBe(5); expect(result.email_address).toBe('support@talova.net'); }); it('creates email address without optional sender_name', async () => { const createData: PlatformEmailAddressCreate = { display_name: 'Info', local_part: 'info', domain: 'talova.net', color: '#6B7280', password: 'password123', is_active: true, is_default: false, }; const mockResponse: PlatformEmailAddress = { id: 6, display_name: 'Info', sender_name: '', effective_sender_name: 'Info', local_part: 'info', domain: 'talova.net', email_address: 'info@talova.net', color: '#6B7280', is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-15T15:00:00Z', updated_at: '2025-01-15T15:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await createPlatformEmailAddress(createData); expect(result.sender_name).toBe(''); expect(result.effective_sender_name).toBe('Info'); }); it('creates email address without assigned user', async () => { const createData: PlatformEmailAddressCreate = { display_name: 'Unassigned', assigned_user_id: null, local_part: 'unassigned', domain: 'talova.net', color: '#9CA3AF', password: 'pass123', is_active: false, is_default: false, }; const mockResponse: PlatformEmailAddress = { id: 7, display_name: 'Unassigned', sender_name: '', effective_sender_name: 'Unassigned', local_part: 'unassigned', domain: 'talova.net', email_address: 'unassigned@talova.net', color: '#9CA3AF', is_active: false, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-15T16:00:00Z', updated_at: '2025-01-15T16:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await createPlatformEmailAddress(createData); expect(result.is_active).toBe(false); }); it('creates email address with is_default set to true', async () => { const createData: PlatformEmailAddressCreate = { display_name: 'Default Email', local_part: 'default', domain: 'talova.net', color: '#F59E0B', password: 'secure-pass', is_active: true, is_default: true, }; const mockResponse: PlatformEmailAddress = { id: 8, display_name: 'Default Email', sender_name: '', effective_sender_name: 'Default Email', local_part: 'default', domain: 'talova.net', email_address: 'default@talova.net', color: '#F59E0B', is_active: true, is_default: true, mail_server_synced: true, emails_processed_count: 0, created_at: '2025-01-15T17:00:00Z', updated_at: '2025-01-15T17:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await createPlatformEmailAddress(createData); expect(result.is_default).toBe(true); }); }); describe('updatePlatformEmailAddress', () => { it('updates email address with full data', async () => { const updateData: PlatformEmailAddressUpdate = { display_name: 'Updated Support', sender_name: 'Updated Sender', assigned_user_id: 20, color: '#EF4444', password: 'new-password-456', is_active: false, is_default: true, }; const mockResponse: PlatformEmailAddress = { id: 1, display_name: 'Updated Support', sender_name: 'Updated Sender', effective_sender_name: 'Updated Sender', local_part: 'support', domain: 'talova.net', email_address: 'support@talova.net', color: '#EF4444', is_active: false, is_default: true, mail_server_synced: true, emails_processed_count: 150, created_at: '2025-01-01T00:00:00Z', updated_at: '2025-01-15T18:00:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); const result = await updatePlatformEmailAddress(1, updateData); expect(apiClient.patch).toHaveBeenCalledWith('/platform/email-addresses/1/', updateData); expect(result).toEqual(mockResponse); expect(result.display_name).toBe('Updated Support'); expect(result.is_active).toBe(false); expect(result.is_default).toBe(true); }); it('updates email address with partial data - only display_name', async () => { const updateData: PlatformEmailAddressUpdate = { display_name: 'New Display Name', }; const mockResponse: PlatformEmailAddress = { id: 2, display_name: 'New Display Name', sender_name: 'Sales', effective_sender_name: 'Sales', local_part: 'sales', domain: 'talova.net', email_address: 'sales@talova.net', color: '#10B981', is_active: true, is_default: false, mail_server_synced: true, emails_processed_count: 50, created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-15T18:30:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); const result = await updatePlatformEmailAddress(2, updateData); expect(apiClient.patch).toHaveBeenCalledWith('/platform/email-addresses/2/', updateData); expect(result.display_name).toBe('New Display Name'); }); it('updates only color', async () => { const updateData: PlatformEmailAddressUpdate = { color: '#8B5CF6', }; const mockResponse: PlatformEmailAddress = { id: 3, display_name: 'Info', sender_name: '', effective_sender_name: 'Info', local_part: 'info', domain: 'talova.net', email_address: 'info@talova.net', color: '#8B5CF6', is_active: true, is_default: false, mail_server_synced: false, emails_processed_count: 0, created_at: '2025-01-14T00:00:00Z', updated_at: '2025-01-15T19:00:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); const result = await updatePlatformEmailAddress(3, updateData); expect(result.color).toBe('#8B5CF6'); }); it('updates only is_active status', async () => { const updateData: PlatformEmailAddressUpdate = { is_active: false, }; const mockResponse: PlatformEmailAddress = { id: 4, display_name: 'Test', sender_name: '', effective_sender_name: 'Test', local_part: 'test', domain: 'talova.net', email_address: 'test@talova.net', color: '#6B7280', is_active: false, is_default: false, mail_server_synced: true, emails_processed_count: 25, created_at: '2025-01-12T00:00:00Z', updated_at: '2025-01-15T19:30:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); const result = await updatePlatformEmailAddress(4, updateData); expect(result.is_active).toBe(false); }); it('updates assigned user to null (unassign)', async () => { const updateData: PlatformEmailAddressUpdate = { assigned_user_id: null, }; const mockResponse: PlatformEmailAddress = { id: 5, display_name: 'Unassigned Now', sender_name: '', effective_sender_name: 'Unassigned Now', local_part: 'unassigned', domain: 'talova.net', email_address: 'unassigned@talova.net', color: '#9CA3AF', is_active: true, is_default: false, mail_server_synced: true, emails_processed_count: 10, created_at: '2025-01-13T00:00:00Z', updated_at: '2025-01-15T20:00:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); await updatePlatformEmailAddress(5, updateData); expect(apiClient.patch).toHaveBeenCalledWith('/platform/email-addresses/5/', updateData); }); it('updates password only', async () => { const updateData: PlatformEmailAddressUpdate = { password: 'new-secure-password', }; const mockResponse: PlatformEmailAddress = { id: 6, display_name: 'Password Updated', sender_name: '', effective_sender_name: 'Password Updated', local_part: 'passupdate', domain: 'talova.net', email_address: 'passupdate@talova.net', color: '#F59E0B', is_active: true, is_default: false, mail_server_synced: true, emails_processed_count: 5, created_at: '2025-01-14T00:00:00Z', updated_at: '2025-01-15T20:30:00Z', }; vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); await updatePlatformEmailAddress(6, updateData); expect(apiClient.patch).toHaveBeenCalledWith('/platform/email-addresses/6/', { password: 'new-secure-password', }); }); }); // ============================================================================ // Delete Operations // ============================================================================ describe('deletePlatformEmailAddress', () => { it('deletes a platform email address by ID', async () => { vi.mocked(apiClient.delete).mockResolvedValue({}); await deletePlatformEmailAddress(1); expect(apiClient.delete).toHaveBeenCalledWith('/platform/email-addresses/1/'); }); it('returns void on successful deletion', async () => { vi.mocked(apiClient.delete).mockResolvedValue({}); const result = await deletePlatformEmailAddress(42); expect(result).toBeUndefined(); }); it('handles deletion with different IDs', async () => { vi.mocked(apiClient.delete).mockResolvedValue({}); await deletePlatformEmailAddress(999); expect(apiClient.delete).toHaveBeenCalledWith('/platform/email-addresses/999/'); }); }); describe('removeLocalPlatformEmailAddress', () => { it('removes email address from database only', async () => { const mockResponse = { success: true, message: 'Email address removed from database. Mail server account retained.', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await removeLocalPlatformEmailAddress(5); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/5/remove_local/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.message).toContain('Mail server account retained'); }); it('handles removal failure', async () => { const mockResponse = { success: false, message: 'Failed to remove email address', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await removeLocalPlatformEmailAddress(10); expect(result.success).toBe(false); }); it('removes with different email address IDs', async () => { const mockResponse = { success: true, message: 'Removed successfully', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); await removeLocalPlatformEmailAddress(123); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/123/remove_local/'); }); }); // ============================================================================ // Sync Operations // ============================================================================ describe('syncPlatformEmailAddress', () => { it('syncs email address to mail server successfully', async () => { const mockResponse: SyncResponse = { success: true, message: 'Email address synced successfully', mail_server_synced: true, last_synced_at: '2025-01-15T21:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await syncPlatformEmailAddress(1); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/1/sync/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.mail_server_synced).toBe(true); expect(result.last_synced_at).toBe('2025-01-15T21:00:00Z'); }); it('handles sync failure with error message', async () => { const mockResponse: SyncResponse = { success: false, message: 'Connection to mail server failed', mail_server_synced: false, last_sync_error: 'Connection timeout', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await syncPlatformEmailAddress(2); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/2/sync/'); expect(result.success).toBe(false); expect(result.last_sync_error).toBe('Connection timeout'); }); it('syncs with different email address IDs', async () => { const mockResponse: SyncResponse = { success: true, message: 'Synced', mail_server_synced: true, }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); await syncPlatformEmailAddress(999); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/999/sync/'); }); }); // ============================================================================ // Connection Testing // ============================================================================ describe('testImapConnection', () => { it('tests IMAP connection successfully', async () => { const mockResponse: TestConnectionResponse = { success: true, message: 'IMAP connection successful', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testImapConnection(1); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/1/test_imap/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.message).toContain('successful'); }); it('handles IMAP connection failure', async () => { const mockResponse: TestConnectionResponse = { success: false, message: 'IMAP connection failed: Invalid credentials', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testImapConnection(2); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/2/test_imap/'); expect(result.success).toBe(false); expect(result.message).toContain('Invalid credentials'); }); it('tests IMAP with different IDs', async () => { const mockResponse: TestConnectionResponse = { success: true, message: 'Connected', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); await testImapConnection(50); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/50/test_imap/'); }); }); describe('testSmtpConnection', () => { it('tests SMTP connection successfully', async () => { const mockResponse: TestConnectionResponse = { success: true, message: 'SMTP connection successful', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testSmtpConnection(1); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/1/test_smtp/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.message).toContain('successful'); }); it('handles SMTP connection failure', async () => { const mockResponse: TestConnectionResponse = { success: false, message: 'SMTP connection failed: Connection refused', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testSmtpConnection(2); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/2/test_smtp/'); expect(result.success).toBe(false); expect(result.message).toContain('Connection refused'); }); it('tests SMTP with different IDs', async () => { const mockResponse: TestConnectionResponse = { success: true, message: 'OK', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); await testSmtpConnection(75); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/75/test_smtp/'); }); }); describe('testMailServerConnection', () => { it('tests mail server SSH connection successfully', async () => { const mockResponse: TestConnectionResponse = { success: true, message: 'SSH connection to mail server successful', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testMailServerConnection(); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/test_mail_server/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); }); it('handles mail server connection failure', async () => { const mockResponse: TestConnectionResponse = { success: false, message: 'SSH connection failed: Authentication error', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await testMailServerConnection(); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/test_mail_server/'); expect(result.success).toBe(false); expect(result.message).toContain('Authentication error'); }); }); // ============================================================================ // Set as Default // ============================================================================ describe('setAsDefault', () => { it('sets an email address as default', async () => { const mockResponse = { success: true, message: 'Email address set as default', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await setAsDefault(3); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/3/set_as_default/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.message).toContain('default'); }); it('handles setting default with different IDs', async () => { const mockResponse = { success: true, message: 'Default updated', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); await setAsDefault(100); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/100/set_as_default/'); }); it('handles failure to set as default', async () => { const mockResponse = { success: false, message: 'Email address must be synced before setting as default', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await setAsDefault(5); expect(result.success).toBe(false); expect(result.message).toContain('must be synced'); }); }); // ============================================================================ // Mail Server Accounts // ============================================================================ describe('getMailServerAccounts', () => { it('fetches all email accounts from mail server', async () => { const mockResponse: MailServerAccountsResponse = { success: true, accounts: [ { email: 'support@talova.net', raw_line: 'support@talova.net:encrypted-password-hash', }, { email: 'sales@talova.net', raw_line: 'sales@talova.net:encrypted-password-hash', }, { email: 'info@talova.net', raw_line: 'info@talova.net:encrypted-password-hash', }, ], count: 3, }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getMailServerAccounts(); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/mail_server_accounts/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.count).toBe(3); expect(result.accounts).toHaveLength(3); expect(result.accounts[0].email).toBe('support@talova.net'); }); it('handles empty mail server accounts', async () => { const mockResponse: MailServerAccountsResponse = { success: true, accounts: [], count: 0, }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getMailServerAccounts(); expect(result.accounts).toEqual([]); expect(result.count).toBe(0); }); it('handles mail server connection failure', async () => { const mockResponse: MailServerAccountsResponse = { success: false, accounts: [], count: 0, }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getMailServerAccounts(); expect(result.success).toBe(false); }); }); // ============================================================================ // Available Domains and Users // ============================================================================ describe('getAvailableDomains', () => { it('fetches available email domains', async () => { const mockResponse = { domains: [ { value: 'talova.net', label: 'talova.net', }, { value: 'example.com', label: 'example.com', }, ], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAvailableDomains(); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/available_domains/'); expect(result).toEqual(mockResponse); expect(result.domains).toHaveLength(2); expect(result.domains[0].value).toBe('talova.net'); }); it('handles single domain', async () => { const mockResponse = { domains: [ { value: 'talova.net', label: 'talova.net', }, ], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAvailableDomains(); expect(result.domains).toHaveLength(1); }); it('handles empty domains list', async () => { const mockResponse = { domains: [], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAvailableDomains(); expect(result.domains).toEqual([]); }); }); describe('getAssignableUsers', () => { it('fetches assignable platform users', async () => { const mockResponse = { users: [ { id: 1, email: 'admin@platform.com', first_name: 'Admin', last_name: 'User', full_name: 'Admin User', role: 'superuser', }, { id: 2, email: 'support@platform.com', first_name: 'Support', last_name: 'Agent', full_name: 'Support Agent', role: 'platform_support', }, { id: 3, email: 'manager@platform.com', first_name: 'Platform', last_name: 'Manager', full_name: 'Platform Manager', role: 'platform_manager', }, ], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAssignableUsers(); expect(apiClient.get).toHaveBeenCalledWith('/platform/email-addresses/assignable_users/'); expect(result).toEqual(mockResponse); expect(result.users).toHaveLength(3); expect(result.users[0].full_name).toBe('Admin User'); expect(result.users[1].role).toBe('platform_support'); }); it('handles empty users list', async () => { const mockResponse = { users: [], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAssignableUsers(); expect(result.users).toEqual([]); }); it('handles users with different roles', async () => { const mockResponse = { users: [ { id: 10, email: 'user@platform.com', first_name: 'Test', last_name: 'User', full_name: 'Test User', role: 'platform_manager', }, ], }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); const result = await getAssignableUsers(); expect(result.users[0].role).toBe('platform_manager'); }); }); // ============================================================================ // Import from Mail Server // ============================================================================ describe('importFromMailServer', () => { it('imports email addresses from mail server successfully', async () => { const mockResponse: ImportFromMailServerResponse = { success: true, imported: [ { id: 10, email: 'support@talova.net', display_name: 'Support', }, { id: 11, email: 'sales@talova.net', display_name: 'Sales', }, ], imported_count: 2, skipped: [ { email: 'info@talova.net', reason: 'Already exists in database', }, ], skipped_count: 1, message: 'Imported 2 email addresses, skipped 1', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await importFromMailServer(); expect(apiClient.post).toHaveBeenCalledWith('/platform/email-addresses/import_from_mail_server/'); expect(result).toEqual(mockResponse); expect(result.success).toBe(true); expect(result.imported_count).toBe(2); expect(result.skipped_count).toBe(1); expect(result.imported).toHaveLength(2); expect(result.skipped).toHaveLength(1); expect(result.imported[0].email).toBe('support@talova.net'); expect(result.skipped[0].reason).toContain('Already exists'); }); it('handles import with no new addresses', async () => { const mockResponse: ImportFromMailServerResponse = { success: true, imported: [], imported_count: 0, skipped: [ { email: 'existing@talova.net', reason: 'Already exists', }, ], skipped_count: 1, message: 'No new email addresses to import', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await importFromMailServer(); expect(result.imported_count).toBe(0); expect(result.skipped_count).toBe(1); expect(result.message).toContain('No new'); }); it('handles import with all addresses imported', async () => { const mockResponse: ImportFromMailServerResponse = { success: true, imported: [ { id: 20, email: 'new1@talova.net', display_name: 'New1', }, { id: 21, email: 'new2@talova.net', display_name: 'New2', }, { id: 22, email: 'new3@talova.net', display_name: 'New3', }, ], imported_count: 3, skipped: [], skipped_count: 0, message: 'Successfully imported 3 email addresses', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await importFromMailServer(); expect(result.imported_count).toBe(3); expect(result.skipped_count).toBe(0); expect(result.skipped).toEqual([]); }); it('handles import failure', async () => { const mockResponse: ImportFromMailServerResponse = { success: false, imported: [], imported_count: 0, skipped: [], skipped_count: 0, message: 'Failed to connect to mail server', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await importFromMailServer(); expect(result.success).toBe(false); expect(result.message).toContain('Failed to connect'); }); it('handles import with validation errors', async () => { const mockResponse: ImportFromMailServerResponse = { success: true, imported: [], imported_count: 0, skipped: [ { email: 'invalid@email', reason: 'Invalid email format', }, { email: 'missing-domain', reason: 'Missing domain', }, ], skipped_count: 2, message: 'Skipped 2 invalid email addresses', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); const result = await importFromMailServer(); expect(result.skipped_count).toBe(2); expect(result.skipped[0].reason).toContain('Invalid'); expect(result.skipped[1].reason).toContain('Missing'); }); }); });