# tests/integration/middleware/test_theme_loading_flow.py """ Integration tests for theme loading end-to-end flow. These tests verify that vendor themes are correctly loaded and injected into request.state through real HTTP requests. Note: These tests use pre-registered routes in middleware_test_routes.py. The conftest patches get_db and settings.platform_domain for proper testing. """ import pytest @pytest.mark.integration @pytest.mark.middleware @pytest.mark.theme class TestThemeLoadingFlow: """Test theme loading through real HTTP requests.""" # ======================================================================== # Basic Theme Loading Tests # ======================================================================== def test_theme_loaded_for_vendor_with_custom_theme(self, client, vendor_with_theme): """Test that custom theme is loaded for vendor with theme.""" response = client.get( "/middleware-test/theme-loading", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_theme"] is True assert data["theme_data"] is not None # Colors are flattened to root level by the route assert data["primary_color"] == "#FF5733" assert data["secondary_color"] == "#33FF57" def test_default_theme_loaded_for_vendor_without_theme( self, client, vendor_with_subdomain ): """Test that default theme is loaded for vendor without custom theme.""" response = client.get( "/middleware-test/theme-default", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_theme"] is True # Default theme should have basic structure assert data["theme_data"] is not None # Colors are flattened to root level by the route assert data["primary_color"] is not None assert data["secondary_color"] is not None def test_no_theme_loaded_without_vendor(self, client): """Test that no theme is loaded when there's no vendor.""" response = client.get( "/middleware-test/theme-no-vendor", headers={"host": "platform.com"} ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is False # No vendor means middleware doesn't set theme (or sets default) # The actual behavior depends on ThemeContextMiddleware implementation # ======================================================================== # Theme Structure Tests # ======================================================================== def test_custom_theme_contains_all_fields(self, client, vendor_with_theme): """Test that custom theme contains all expected fields.""" response = client.get( "/middleware-test/theme-fields", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["primary_color"] == "#FF5733" assert data["secondary_color"] == "#33FF57" assert data["logo_url"] == "/static/vendors/themedvendor/logo.png" assert data["favicon_url"] == "/static/vendors/themedvendor/favicon.ico" assert "background" in data["custom_css"] def test_default_theme_structure(self, client, vendor_with_subdomain): """Test that default theme has expected structure.""" response = client.get( "/middleware-test/theme-structure", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() # Default theme should have basic structure assert data["has_primary_color"] is True assert data["has_secondary_color"] is True # ======================================================================== # Theme Loading for Different Contexts Tests # ======================================================================== def test_theme_loaded_in_shop_context(self, client, vendor_with_theme): """Test that theme is loaded in SHOP context.""" response = client.get( "/shop/middleware-test/theme", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["context_type"] == "shop" assert data["has_theme"] is True assert data["theme_primary"] == "#FF5733" # Note: Theme loading in vendor dashboard context is tested via unit tests in # tests/unit/middleware/test_theme_context.py since /vendor/* integration test # routes are shadowed by the catch-all /vendor/{vendor_code}/{slug} route. def test_theme_loaded_in_api_context_with_vendor(self, client, vendor_with_theme): """Test API context detection and theme behavior with vendor subdomain. Note: For API context, vendor detection from subdomain may be skipped depending on middleware configuration. This test verifies the context is correctly set to 'api' regardless of vendor detection. """ response = client.get( "/api/middleware-test/theme", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["context_type"] == "api" # Vendor and theme detection for API routes depends on middleware config # The important assertion is that context_type is correctly set to 'api' def test_no_theme_in_admin_context(self, client): """Test theme behavior in ADMIN context (no vendor).""" response = client.get("/admin/middleware-test/no-theme") assert response.status_code == 200 data = response.json() assert data["context_type"] == "admin" # Admin context has no vendor - theme behavior depends on middleware config # ======================================================================== # Theme Loading with Different Routing Modes Tests # ======================================================================== def test_theme_loaded_with_subdomain_routing(self, client, vendor_with_theme): """Test theme loading with subdomain routing.""" response = client.get( "/middleware-test/theme-fields", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["logo_url"] == "/static/vendors/themedvendor/logo.png" def test_theme_loaded_with_custom_domain_routing( self, client, vendor_with_custom_domain, db ): """Test theme loading behavior with custom domain routing. Note: Custom domain detection requires the domain to be verified in the database. This test verifies the theme loading mechanism when a custom domain is used. """ from app.modules.cms.models import VendorTheme # Add theme to custom domain vendor theme = VendorTheme( vendor_id=vendor_with_custom_domain.id, colors={ "primary": "#123456", "secondary": "#654321", "accent": "#ec4899", "background": "#ffffff", "text": "#1f2937", "border": "#e5e7eb", }, ) db.add(theme) db.commit() response = client.get( "/middleware-test/theme-loading", headers={"host": "customdomain.com"} ) assert response.status_code == 200 data = response.json() # Custom domain vendor detection depends on domain verification status # If vendor is detected and has custom theme, verify it's loaded # Otherwise, default theme may be applied # ======================================================================== # Theme Dependency on Vendor Context Tests # ======================================================================== def test_theme_middleware_depends_on_vendor_middleware( self, client, vendor_with_theme ): """Test that theme loading depends on vendor being detected first.""" response = client.get( "/middleware-test/theme-vendor-dependency", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is True assert data["vendor_id"] == vendor_with_theme.id assert data["has_theme"] is True # ======================================================================== # Theme Caching and Performance Tests # ======================================================================== def test_theme_loaded_consistently_across_requests(self, client, vendor_with_theme): """Test that theme is loaded consistently across multiple requests.""" # Make multiple requests responses = [] for _ in range(3): response = client.get( "/middleware-test/theme-consistency", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) responses.append(response.json()) # All responses should have same theme assert all(r["theme_primary"] == "#FF5733" for r in responses) # ======================================================================== # Edge Cases and Error Handling Tests # ======================================================================== def test_theme_gracefully_handles_missing_theme_fields( self, client, vendor_with_subdomain ): """Test that missing theme fields are handled gracefully.""" response = client.get( "/middleware-test/theme-partial", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_theme"] is True # Should have defaults for missing fields (route provides "default" fallback) assert data["primary_color"] is not None def test_theme_dict_is_mutable(self, client, vendor_with_theme): """Test that theme dict can be accessed and read from.""" response = client.get( "/middleware-test/theme-mutable", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["can_read"] is True assert data["value"] == "#FF5733"