# tests/unit/models/test_merchant_domain.py """Unit tests for MerchantDomain model and related model properties.""" import uuid from datetime import UTC, datetime import pytest from app.modules.tenancy.models.merchant_domain import MerchantDomain from app.modules.tenancy.models.store_domain import StoreDomain # ============================================================================= # MODEL TESTS # ============================================================================= @pytest.mark.unit @pytest.mark.tenancy class TestMerchantDomainModel: """Test suite for MerchantDomain model.""" def test_create_merchant_domain(self, db, test_merchant): """Test creating a MerchantDomain with required fields.""" unique_id = str(uuid.uuid4())[:8] domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"test{unique_id}.example.com", is_primary=True, verification_token=f"token_{unique_id}", ) db.add(domain) db.commit() db.refresh(domain) assert domain.id is not None assert domain.merchant_id == test_merchant.id assert domain.is_primary is True assert domain.is_active is True # default assert domain.is_verified is False # default assert domain.ssl_status == "pending" # default assert domain.verified_at is None assert domain.platform_id is None def test_merchant_domain_defaults(self, db, test_merchant): """Test default values for MerchantDomain.""" unique_id = str(uuid.uuid4())[:8] domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"defaults{unique_id}.example.com", verification_token=f"dtoken_{unique_id}", ) db.add(domain) db.commit() db.refresh(domain) assert domain.is_primary is True assert domain.is_active is True assert domain.is_verified is False assert domain.ssl_status == "pending" def test_merchant_domain_repr(self, db, test_merchant): """Test string representation.""" domain = MerchantDomain( merchant_id=test_merchant.id, domain="repr.example.com", ) assert "repr.example.com" in repr(domain) assert str(test_merchant.id) in repr(domain) def test_merchant_domain_full_url(self): """Test full_url property.""" domain = MerchantDomain(domain="test.example.com") assert domain.full_url == "https://test.example.com" def test_normalize_domain_removes_protocol(self): """Test normalize_domain strips protocols.""" assert MerchantDomain.normalize_domain("https://example.com") == "example.com" assert MerchantDomain.normalize_domain("http://example.com") == "example.com" def test_normalize_domain_removes_trailing_slash(self): """Test normalize_domain strips trailing slashes.""" assert MerchantDomain.normalize_domain("example.com/") == "example.com" def test_normalize_domain_lowercases(self): """Test normalize_domain converts to lowercase.""" assert MerchantDomain.normalize_domain("EXAMPLE.COM") == "example.com" def test_unique_domain_constraint(self, db, test_merchant): """Test that domain must be unique across all merchant domains.""" unique_id = str(uuid.uuid4())[:8] domain_name = f"unique{unique_id}.example.com" domain1 = MerchantDomain( merchant_id=test_merchant.id, domain=domain_name, verification_token=f"t1_{unique_id}", ) db.add(domain1) db.commit() domain2 = MerchantDomain( merchant_id=test_merchant.id, domain=domain_name, verification_token=f"t2_{unique_id}", ) db.add(domain2) with pytest.raises(Exception): # IntegrityError db.commit() db.rollback() # ============================================================================= # MERCHANT.primary_domain PROPERTY TESTS # ============================================================================= @pytest.mark.unit @pytest.mark.tenancy class TestMerchantPrimaryDomain: """Test Merchant.primary_domain property.""" def test_primary_domain_returns_active_verified_primary(self, db, test_merchant): """Test primary_domain returns domain when active, verified, and primary.""" unique_id = str(uuid.uuid4())[:8] domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"primary{unique_id}.example.com", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"pt_{unique_id}", ) db.add(domain) db.commit() db.refresh(test_merchant) assert test_merchant.primary_domain == f"primary{unique_id}.example.com" def test_primary_domain_returns_none_when_no_domains(self, db, test_merchant): """Test primary_domain returns None when merchant has no domains.""" db.refresh(test_merchant) # Fresh merchant without any domains added in this test # Need to check if it may have domains from other fixtures # Just verify the property works without error result = test_merchant.primary_domain assert result is None or isinstance(result, str) def test_primary_domain_returns_none_when_inactive(self, db, test_merchant): """Test primary_domain returns None when domain is inactive.""" unique_id = str(uuid.uuid4())[:8] domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"inactive{unique_id}.example.com", is_primary=True, is_active=False, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"it_{unique_id}", ) db.add(domain) db.commit() db.refresh(test_merchant) assert test_merchant.primary_domain is None def test_primary_domain_returns_none_when_unverified(self, db, test_merchant): """Test primary_domain returns None when domain is unverified.""" unique_id = str(uuid.uuid4())[:8] domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"unverified{unique_id}.example.com", is_primary=True, is_active=True, is_verified=False, verification_token=f"ut_{unique_id}", ) db.add(domain) db.commit() db.refresh(test_merchant) assert test_merchant.primary_domain is None # ============================================================================= # STORE.effective_domain PROPERTY TESTS # ============================================================================= @pytest.mark.unit @pytest.mark.tenancy class TestStoreEffectiveDomain: """Test Store.effective_domain inheritance chain.""" def test_effective_domain_returns_store_domain_when_present(self, db, test_store): """Test effective_domain returns store's own custom domain (highest priority).""" unique_id = str(uuid.uuid4())[:8] store_domain = StoreDomain( store_id=test_store.id, domain=f"storeover{unique_id}.example.com", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"sd_{unique_id}", ) db.add(store_domain) db.commit() db.refresh(test_store) assert test_store.effective_domain == f"storeover{unique_id}.example.com" def test_effective_domain_returns_merchant_domain_when_no_store_domain( self, db, test_store, test_merchant ): """Test effective_domain returns merchant domain when no store domain.""" unique_id = str(uuid.uuid4())[:8] merchant_domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"merchant{unique_id}.example.com", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"md_{unique_id}", ) db.add(merchant_domain) db.commit() db.refresh(test_store) db.refresh(test_merchant) assert test_store.effective_domain == f"merchant{unique_id}.example.com" def test_effective_domain_returns_subdomain_fallback(self, db, test_store): """Test effective_domain returns subdomain fallback when no custom domains.""" db.refresh(test_store) # With no store or merchant domains, should fall back to subdomain result = test_store.effective_domain assert test_store.subdomain in result def test_effective_domain_store_domain_overrides_merchant_domain( self, db, test_store, test_merchant ): """Test that store domain takes priority over merchant domain.""" unique_id = str(uuid.uuid4())[:8] # Add merchant domain merchant_domain = MerchantDomain( merchant_id=test_merchant.id, domain=f"merchantpri{unique_id}.example.com", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"mpri_{unique_id}", ) db.add(merchant_domain) # Add store domain (should take priority) store_domain = StoreDomain( store_id=test_store.id, domain=f"storepri{unique_id}.example.com", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"spri_{unique_id}", ) db.add(store_domain) db.commit() db.refresh(test_store) db.refresh(test_merchant) assert test_store.effective_domain == f"storepri{unique_id}.example.com"