# tests/integration/api/v1/test_vendor_api_dashboard.py """ Integration tests for vendor dashboard API endpoints. Tests cover: 1. Dashboard stats retrieval 2. Vendor-specific data isolation 3. Permission checks 4. Data accuracy """ import pytest @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorDashboardAPI: """Test vendor dashboard stats endpoint""" def test_get_dashboard_stats_structure( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test dashboard stats returns correct data structure""" response = client.get( "/api/v1/vendor/dashboard/stats", headers=vendor_user_headers ) assert response.status_code == 200 data = response.json() # Verify top-level structure assert "vendor" in data assert "products" in data assert "orders" in data assert "customers" in data assert "revenue" in data # Verify vendor info assert "id" in data["vendor"] assert "name" in data["vendor"] assert "vendor_code" in data["vendor"] assert data["vendor"]["id"] == test_vendor_with_vendor_user.id # Verify products stats assert "total" in data["products"] assert "active" in data["products"] assert isinstance(data["products"]["total"], int) assert isinstance(data["products"]["active"], int) # Verify orders stats assert "total" in data["orders"] assert "pending" in data["orders"] assert "completed" in data["orders"] # Verify customers stats assert "total" in data["customers"] assert "active" in data["customers"] # Verify revenue stats assert "total" in data["revenue"] assert "this_month" in data["revenue"] def test_dashboard_stats_vendor_isolation( self, client, db, test_vendor_user, auth_manager ): """Test that dashboard stats only show data for the authenticated vendor""" from models.database.marketplace_product import MarketplaceProduct from models.database.product import Product from models.database.vendor import Vendor, VendorUser # Create two separate vendors with different data vendor1 = Vendor( vendor_code="VENDOR1", subdomain="vendor1", name="Vendor One", owner_user_id=test_vendor_user.id, is_active=True, is_verified=True, ) db.add(vendor1) db.commit() db.refresh(vendor1) # Associate vendor1 with test_vendor_user vendor_user1 = VendorUser( vendor_id=vendor1.id, user_id=test_vendor_user.id, is_owner=True, is_active=True, ) db.add(vendor_user1) db.commit() # Create marketplace product for vendor1 mp1 = MarketplaceProduct( gtin="1234567890123", title="Product for Vendor 1", is_active=True, ) db.add(mp1) db.commit() # Create products for vendor1 for i in range(3): product = Product( vendor_id=vendor1.id, marketplace_product_id=mp1.id, price=10.0 + i, is_active=True, ) db.add(product) db.commit() # Get token for vendor1 user token_data = auth_manager.create_access_token(test_vendor_user) vendor1_headers = {"Authorization": f"Bearer {token_data['access_token']}"} # Get stats for vendor1 response = client.get("/api/v1/vendor/dashboard/stats", headers=vendor1_headers) assert response.status_code == 200 data = response.json() # Should show 3 products for vendor1 assert data["vendor"]["id"] == vendor1.id assert data["products"]["total"] == 3 def test_dashboard_stats_without_vendor_association(self, client, db, auth_manager): """Test dashboard stats for user not associated with any vendor""" from models.database.user import User # Create vendor user without vendor association hashed_password = auth_manager.hash_password("testpass123") orphan_user = User( email="orphan@example.com", username="orphanvendor", hashed_password=hashed_password, role="vendor", is_active=True, ) db.add(orphan_user) db.commit() db.refresh(orphan_user) # Get token token_data = auth_manager.create_access_token(orphan_user) headers = {"Authorization": f"Bearer {token_data['access_token']}"} # Try to get dashboard stats response = client.get("/api/v1/vendor/dashboard/stats", headers=headers) # Should fail - user not associated with vendor assert response.status_code == 403 data = response.json() assert "not associated with any vendor" in data["message"] def test_dashboard_stats_with_inactive_vendor( self, client, db, test_vendor_user, auth_manager ): """Test dashboard stats for inactive vendor""" from models.database.vendor import Vendor, VendorUser # Create inactive vendor vendor = Vendor( vendor_code="INACTIVE", subdomain="inactive", name="Inactive Vendor", owner_user_id=test_vendor_user.id, is_active=False, # Inactive is_verified=True, ) db.add(vendor) db.commit() # Associate with user vendor_user = VendorUser( vendor_id=vendor.id, user_id=test_vendor_user.id, is_owner=True, is_active=True, ) db.add(vendor_user) db.commit() # Get token token_data = auth_manager.create_access_token(test_vendor_user) headers = {"Authorization": f"Bearer {token_data['access_token']}"} # Try to get dashboard stats response = client.get("/api/v1/vendor/dashboard/stats", headers=headers) # Should fail - vendor is inactive assert response.status_code == 404 data = response.json() assert "not found or inactive" in data["message"] def test_dashboard_stats_empty_vendor( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test dashboard stats for vendor with no data""" response = client.get( "/api/v1/vendor/dashboard/stats", headers=vendor_user_headers ) assert response.status_code == 200 data = response.json() # Should return zeros for empty vendor assert data["products"]["total"] == 0 assert data["products"]["active"] == 0 assert data["orders"]["total"] == 0 assert data["customers"]["total"] == 0 assert data["revenue"]["total"] == 0 def test_dashboard_stats_with_products( self, client, db, vendor_user_headers, test_vendor_with_vendor_user ): """Test dashboard stats accuracy with actual products""" from models.database.marketplace_product import MarketplaceProduct from models.database.product import Product # Create marketplace products mp = MarketplaceProduct( gtin="1234567890124", title="Test Product", is_active=True, ) db.add(mp) db.commit() # Create products (3 active, 2 inactive) for i in range(5): product = Product( vendor_id=test_vendor_with_vendor_user.id, marketplace_product_id=mp.id, price=10.0 + i, is_active=(i < 3), # First 3 are active ) db.add(product) db.commit() # Get stats response = client.get( "/api/v1/vendor/dashboard/stats", headers=vendor_user_headers ) assert response.status_code == 200 data = response.json() assert data["products"]["total"] == 5 assert data["products"]["active"] == 3 def test_dashboard_stats_response_time( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test that dashboard stats responds quickly""" import time start_time = time.time() response = client.get( "/api/v1/vendor/dashboard/stats", headers=vendor_user_headers ) end_time = time.time() assert response.status_code == 200 # Should respond in less than 2 seconds assert (end_time - start_time) < 2.0 def test_dashboard_stats_caching_behavior( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test that dashboard stats can be called multiple times""" # Make multiple requests responses = [] for _ in range(3): response = client.get( "/api/v1/vendor/dashboard/stats", headers=vendor_user_headers ) responses.append(response) # All should succeed for response in responses: assert response.status_code == 200 # All should return consistent data data_list = [r.json() for r in responses] for data in data_list[1:]: assert data["vendor"]["id"] == data_list[0]["vendor"]["id"] assert data["products"]["total"] == data_list[0]["products"]["total"]