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 { searchDomains, getDomainPrices, registerDomain, getRegisteredDomains, getDomainRegistration, updateNameservers, toggleAutoRenew, renewDomain, syncDomain, getSearchHistory, DomainAvailability, DomainPrice, DomainRegisterRequest, DomainRegistration, DomainSearchHistory, } from '../domains'; import apiClient from '../client'; describe('domains API', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('searchDomains', () => { it('searches for domains with default TLDs', async () => { const mockResults: DomainAvailability[] = [ { domain: 'example.com', available: true, price: 12.99, premium: false, premium_price: null, }, { domain: 'example.net', available: false, price: null, premium: false, premium_price: null, }, { domain: 'example.org', available: true, price: 14.99, premium: false, premium_price: null, }, ]; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResults }); const result = await searchDomains('example'); expect(apiClient.post).toHaveBeenCalledWith('/domains/search/search/', { query: 'example', tlds: ['.com', '.net', '.org'], }); expect(result).toEqual(mockResults); expect(result).toHaveLength(3); }); it('searches for domains with custom TLDs', async () => { const mockResults: DomainAvailability[] = [ { domain: 'mybusiness.io', available: true, price: 39.99, premium: false, premium_price: null, }, { domain: 'mybusiness.dev', available: true, price: 12.99, premium: false, premium_price: null, }, ]; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResults }); const result = await searchDomains('mybusiness', ['.io', '.dev']); expect(apiClient.post).toHaveBeenCalledWith('/domains/search/search/', { query: 'mybusiness', tlds: ['.io', '.dev'], }); expect(result).toEqual(mockResults); }); it('handles premium domain results', async () => { const mockResults: DomainAvailability[] = [ { domain: 'premium.com', available: true, price: 12.99, premium: true, premium_price: 5000.0, }, ]; vi.mocked(apiClient.post).mockResolvedValue({ data: mockResults }); const result = await searchDomains('premium'); expect(result[0].premium).toBe(true); expect(result[0].premium_price).toBe(5000.0); }); }); describe('getDomainPrices', () => { it('fetches domain prices for all TLDs', async () => { const mockPrices: DomainPrice[] = [ { tld: '.com', registration: 12.99, renewal: 14.99, transfer: 12.99, }, { tld: '.net', registration: 14.99, renewal: 16.99, transfer: 14.99, }, { tld: '.org', registration: 14.99, renewal: 16.99, transfer: 14.99, }, { tld: '.io', registration: 39.99, renewal: 39.99, transfer: 39.99, }, ]; vi.mocked(apiClient.get).mockResolvedValue({ data: mockPrices }); const result = await getDomainPrices(); expect(apiClient.get).toHaveBeenCalledWith('/domains/search/prices/'); expect(result).toEqual(mockPrices); expect(result).toHaveLength(4); }); }); describe('registerDomain', () => { it('registers a new domain with full contact information', async () => { const registerRequest: DomainRegisterRequest = { domain: 'newbusiness.com', years: 2, whois_privacy: true, auto_renew: true, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], contact: { first_name: 'John', last_name: 'Doe', email: 'john@example.com', phone: '+1.5551234567', address: '123 Main St', city: 'New York', state: 'NY', zip_code: '10001', country: 'US', }, auto_configure: true, }; const mockRegistration: DomainRegistration = { id: 1, domain: 'newbusiness.com', status: 'pending', registered_at: null, expires_at: null, auto_renew: true, whois_privacy: true, purchase_price: 25.98, renewal_price: null, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], days_until_expiry: null, is_expiring_soon: false, created_at: '2024-01-15T10:00:00Z', registrant_first_name: 'John', registrant_last_name: 'Doe', registrant_email: 'john@example.com', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockRegistration }); const result = await registerDomain(registerRequest); expect(apiClient.post).toHaveBeenCalledWith('/domains/search/register/', registerRequest); expect(result).toEqual(mockRegistration); expect(result.status).toBe('pending'); }); it('registers domain without optional nameservers', async () => { const registerRequest: DomainRegisterRequest = { domain: 'simple.com', years: 1, whois_privacy: false, auto_renew: false, contact: { first_name: 'Jane', last_name: 'Smith', email: 'jane@example.com', phone: '+1.5559876543', address: '456 Oak Ave', city: 'Boston', state: 'MA', zip_code: '02101', country: 'US', }, auto_configure: false, }; const mockRegistration: DomainRegistration = { id: 2, domain: 'simple.com', status: 'pending', registered_at: null, expires_at: null, auto_renew: false, whois_privacy: false, purchase_price: 12.99, renewal_price: null, nameservers: [], days_until_expiry: null, is_expiring_soon: false, created_at: '2024-01-15T10:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockRegistration }); const result = await registerDomain(registerRequest); expect(result.whois_privacy).toBe(false); expect(result.auto_renew).toBe(false); expect(result.nameservers).toEqual([]); }); }); describe('getRegisteredDomains', () => { it('fetches all registered domains for current business', async () => { const mockDomains: DomainRegistration[] = [ { id: 1, domain: 'business1.com', status: 'active', registered_at: '2023-01-15T10:00:00Z', expires_at: '2025-01-15T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], days_until_expiry: 365, is_expiring_soon: false, created_at: '2023-01-15T09:00:00Z', }, { id: 2, domain: 'business2.net', status: 'active', registered_at: '2024-01-01T10:00:00Z', expires_at: '2024-03-01T10:00:00Z', auto_renew: false, whois_privacy: false, purchase_price: 14.99, renewal_price: 16.99, nameservers: ['ns1.example.com', 'ns2.example.com'], days_until_expiry: 30, is_expiring_soon: true, created_at: '2024-01-01T09:00:00Z', }, ]; vi.mocked(apiClient.get).mockResolvedValue({ data: mockDomains }); const result = await getRegisteredDomains(); expect(apiClient.get).toHaveBeenCalledWith('/domains/registrations/'); expect(result).toEqual(mockDomains); expect(result).toHaveLength(2); expect(result[1].is_expiring_soon).toBe(true); }); it('handles empty domain list', async () => { vi.mocked(apiClient.get).mockResolvedValue({ data: [] }); const result = await getRegisteredDomains(); expect(result).toEqual([]); expect(result).toHaveLength(0); }); }); describe('getDomainRegistration', () => { it('fetches a single domain registration by ID', async () => { const mockDomain: DomainRegistration = { id: 5, domain: 'example.com', status: 'active', registered_at: '2023-06-01T10:00:00Z', expires_at: '2025-06-01T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com', 'ns3.digitalocean.com'], days_until_expiry: 500, is_expiring_soon: false, created_at: '2023-06-01T09:30:00Z', registrant_first_name: 'Alice', registrant_last_name: 'Johnson', registrant_email: 'alice@example.com', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockDomain }); const result = await getDomainRegistration(5); expect(apiClient.get).toHaveBeenCalledWith('/domains/registrations/5/'); expect(result).toEqual(mockDomain); expect(result.registrant_email).toBe('alice@example.com'); }); it('fetches domain with failed status', async () => { const mockDomain: DomainRegistration = { id: 10, domain: 'failed.com', status: 'failed', registered_at: null, expires_at: null, auto_renew: false, whois_privacy: false, purchase_price: null, renewal_price: null, nameservers: [], days_until_expiry: null, is_expiring_soon: false, created_at: '2024-01-10T10:00:00Z', }; vi.mocked(apiClient.get).mockResolvedValue({ data: mockDomain }); const result = await getDomainRegistration(10); expect(result.status).toBe('failed'); expect(result.registered_at).toBeNull(); }); }); describe('updateNameservers', () => { it('updates nameservers for a domain', async () => { const nameservers = [ 'ns1.customdns.com', 'ns2.customdns.com', 'ns3.customdns.com', 'ns4.customdns.com', ]; const mockUpdated: DomainRegistration = { id: 3, domain: 'updated.com', status: 'active', registered_at: '2023-01-01T10:00:00Z', expires_at: '2024-01-01T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: nameservers, days_until_expiry: 100, is_expiring_soon: false, created_at: '2023-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockUpdated }); const result = await updateNameservers(3, nameservers); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/3/update_nameservers/', { nameservers: nameservers, }); expect(result.nameservers).toEqual(nameservers); expect(result.nameservers).toHaveLength(4); }); it('updates to default DigitalOcean nameservers', async () => { const nameservers = ['ns1.digitalocean.com', 'ns2.digitalocean.com', 'ns3.digitalocean.com']; const mockUpdated: DomainRegistration = { id: 7, domain: 'reset.com', status: 'active', registered_at: '2023-01-01T10:00:00Z', expires_at: '2024-01-01T10:00:00Z', auto_renew: false, whois_privacy: false, purchase_price: 12.99, renewal_price: 14.99, nameservers: nameservers, days_until_expiry: 200, is_expiring_soon: false, created_at: '2023-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockUpdated }); const result = await updateNameservers(7, nameservers); expect(result.nameservers).toEqual(nameservers); }); }); describe('toggleAutoRenew', () => { it('enables auto-renewal for a domain', async () => { const mockUpdated: DomainRegistration = { id: 4, domain: 'autorenew.com', status: 'active', registered_at: '2023-01-01T10:00:00Z', expires_at: '2024-01-01T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], days_until_expiry: 150, is_expiring_soon: false, created_at: '2023-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockUpdated }); const result = await toggleAutoRenew(4, true); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/4/toggle_auto_renew/', { auto_renew: true, }); expect(result.auto_renew).toBe(true); }); it('disables auto-renewal for a domain', async () => { const mockUpdated: DomainRegistration = { id: 6, domain: 'noautorenew.com', status: 'active', registered_at: '2023-01-01T10:00:00Z', expires_at: '2024-01-01T10:00:00Z', auto_renew: false, whois_privacy: false, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.example.com', 'ns2.example.com'], days_until_expiry: 60, is_expiring_soon: true, created_at: '2023-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockUpdated }); const result = await toggleAutoRenew(6, false); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/6/toggle_auto_renew/', { auto_renew: false, }); expect(result.auto_renew).toBe(false); }); }); describe('renewDomain', () => { it('renews domain for 1 year (default)', async () => { const mockRenewed: DomainRegistration = { id: 8, domain: 'renew.com', status: 'active', registered_at: '2022-01-01T10:00:00Z', expires_at: '2025-01-01T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], days_until_expiry: 365, is_expiring_soon: false, created_at: '2022-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockRenewed }); const result = await renewDomain(8); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/8/renew/', { years: 1, }); expect(result).toEqual(mockRenewed); }); it('renews domain for multiple years', async () => { const mockRenewed: DomainRegistration = { id: 9, domain: 'longterm.com', status: 'active', registered_at: '2022-01-01T10:00:00Z', expires_at: '2027-01-01T10:00:00Z', auto_renew: false, whois_privacy: false, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.example.com', 'ns2.example.com'], days_until_expiry: 1095, is_expiring_soon: false, created_at: '2022-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockRenewed }); const result = await renewDomain(9, 5); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/9/renew/', { years: 5, }); expect(result).toEqual(mockRenewed); }); it('renews domain for 2 years', async () => { const mockRenewed: DomainRegistration = { id: 11, domain: 'twoyears.com', status: 'active', registered_at: '2023-01-01T10:00:00Z', expires_at: '2026-01-01T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.digitalocean.com', 'ns2.digitalocean.com'], days_until_expiry: 730, is_expiring_soon: false, created_at: '2023-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockRenewed }); const result = await renewDomain(11, 2); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/11/renew/', { years: 2, }); expect(result.expires_at).toBe('2026-01-01T10:00:00Z'); }); }); describe('syncDomain', () => { it('syncs domain information from NameSilo', async () => { const mockSynced: DomainRegistration = { id: 12, domain: 'synced.com', status: 'active', registered_at: '2023-05-15T10:00:00Z', expires_at: '2024-05-15T10:00:00Z', auto_renew: true, whois_privacy: true, purchase_price: 12.99, renewal_price: 14.99, nameservers: ['ns1.namesilo.com', 'ns2.namesilo.com'], days_until_expiry: 120, is_expiring_soon: false, created_at: '2023-05-15T09:30:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockSynced }); const result = await syncDomain(12); expect(apiClient.post).toHaveBeenCalledWith('/domains/registrations/12/sync/'); expect(result).toEqual(mockSynced); }); it('syncs domain and updates status', async () => { const mockSynced: DomainRegistration = { id: 13, domain: 'expired.com', status: 'expired', registered_at: '2020-01-01T10:00:00Z', expires_at: '2023-01-01T10:00:00Z', auto_renew: false, whois_privacy: false, purchase_price: 12.99, renewal_price: 14.99, nameservers: [], days_until_expiry: -365, is_expiring_soon: false, created_at: '2020-01-01T09:00:00Z', }; vi.mocked(apiClient.post).mockResolvedValue({ data: mockSynced }); const result = await syncDomain(13); expect(result.status).toBe('expired'); expect(result.days_until_expiry).toBeLessThan(0); }); }); describe('getSearchHistory', () => { it('fetches domain search history', async () => { const mockHistory: DomainSearchHistory[] = [ { id: 1, searched_domain: 'example.com', was_available: true, price: 12.99, searched_at: '2024-01-15T10:00:00Z', }, { id: 2, searched_domain: 'taken.com', was_available: false, price: null, searched_at: '2024-01-15T10:05:00Z', }, { id: 3, searched_domain: 'premium.com', was_available: true, price: 5000.0, searched_at: '2024-01-15T10:10:00Z', }, ]; vi.mocked(apiClient.get).mockResolvedValue({ data: mockHistory }); const result = await getSearchHistory(); expect(apiClient.get).toHaveBeenCalledWith('/domains/history/'); expect(result).toEqual(mockHistory); expect(result).toHaveLength(3); expect(result[1].was_available).toBe(false); expect(result[2].price).toBe(5000.0); }); it('handles empty search history', async () => { vi.mocked(apiClient.get).mockResolvedValue({ data: [] }); const result = await getSearchHistory(); expect(result).toEqual([]); expect(result).toHaveLength(0); }); }); });