# tests/integration/api/v1/vendor/test_onboarding.py """ Integration tests for vendor onboarding API endpoints. Tests cover: 1. Onboarding status retrieval 2. Step 1: Company profile setup 3. Step 2: Letzshop API configuration 4. Step 3: Product import configuration 5. Step 4: Order sync (mocked) 6. Step order validation (can't skip ahead) 7. Onboarding completion flow """ import pytest from models.database.onboarding import OnboardingStatus, OnboardingStep, VendorOnboarding @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingStatusAPI: """Test onboarding status endpoint""" def test_get_status_creates_onboarding_if_missing( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test that getting status creates onboarding record if none exists""" # First ensure no onboarding exists existing = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if existing: db.delete(existing) db.commit() response = client.get( "/api/v1/vendor/onboarding/status", headers=vendor_user_headers ) assert response.status_code == 200 data = response.json() assert data["vendor_id"] == test_vendor_with_vendor_user.id assert data["status"] == OnboardingStatus.NOT_STARTED.value assert data["current_step"] == OnboardingStep.COMPANY_PROFILE.value assert data["completed_steps_count"] == 0 assert data["total_steps"] == 4 assert data["is_completed"] is False def test_get_status_structure( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test status response has correct structure""" response = client.get( "/api/v1/vendor/onboarding/status", headers=vendor_user_headers ) assert response.status_code == 200 data = response.json() # Verify structure assert "id" in data assert "vendor_id" in data assert "status" in data assert "current_step" in data assert "company_profile" in data assert "letzshop_api" in data assert "product_import" in data assert "order_sync" in data assert "completion_percentage" in data assert "completed_steps_count" in data assert "total_steps" in data assert "is_completed" in data def test_get_status_requires_auth(self, client): """Test that onboarding status requires authentication""" response = client.get("/api/v1/vendor/onboarding/status") assert response.status_code == 401 @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingStep1API: """Test Step 1: Company Profile endpoints""" def test_get_company_profile_data( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test getting company profile data""" response = client.get( "/api/v1/vendor/onboarding/step/company-profile", headers=vendor_user_headers, ) assert response.status_code == 200 data = response.json() # Should return pre-filled data assert "brand_name" in data assert "contact_email" in data assert "default_language" in data def test_save_company_profile_success( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test saving company profile completes step 1""" # First ensure clean state existing = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if existing: db.delete(existing) db.commit() response = client.post( "/api/v1/vendor/onboarding/step/company-profile", headers=vendor_user_headers, json={ "company_name": "Test Company Ltd", "brand_name": "Test Brand", "description": "A test company for testing", "contact_email": "test@example.com", "contact_phone": "+352123456789", "website": "https://test.example.com", "business_address": "123 Test Street, Luxembourg", "tax_number": "LU12345678", "default_language": "fr", "dashboard_language": "en", }, ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["step_completed"] is True assert data["next_step"] == OnboardingStep.LETZSHOP_API.value # Verify onboarding was updated onboarding = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) db.refresh(onboarding) assert onboarding.step_company_profile_completed is True assert onboarding.status == OnboardingStatus.IN_PROGRESS.value def test_save_company_profile_with_minimal_data( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test saving company profile with minimal data""" # Clear existing onboarding existing = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if existing: db.delete(existing) db.commit() response = client.post( "/api/v1/vendor/onboarding/step/company-profile", headers=vendor_user_headers, json={ "default_language": "fr", "dashboard_language": "fr", }, ) assert response.status_code == 200 data = response.json() assert data["success"] is True @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingStep2API: """Test Step 2: Letzshop API Configuration endpoints""" def test_letzshop_api_test_endpoint( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test the Letzshop API test endpoint""" response = client.post( "/api/v1/vendor/onboarding/step/letzshop-api/test", headers=vendor_user_headers, json={ "api_key": "test_invalid_key_12345", "shop_slug": "test-shop", }, ) assert response.status_code == 200 data = response.json() # Response should indicate success or failure assert "success" in data assert "message" in data def test_letzshop_api_requires_step1_complete( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test that step 2 requires step 1 to be completed""" # Ensure fresh state with no steps completed existing = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if existing: db.delete(existing) db.commit() # Try to save step 2 directly response = client.post( "/api/v1/vendor/onboarding/step/letzshop-api", headers=vendor_user_headers, json={ "api_key": "test_api_key_12345678901234567890", "shop_slug": "test-shop", }, ) # Should fail because step 1 is not complete assert response.status_code == 422 # Validation error data = response.json() assert "step" in str(data).lower() or "complete" in str(data).lower() @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingStep3API: """Test Step 3: Product Import Configuration endpoints""" def test_get_product_import_config( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test getting product import configuration""" response = client.get( "/api/v1/vendor/onboarding/step/product-import", headers=vendor_user_headers, ) assert response.status_code == 200 data = response.json() assert "csv_url_fr" in data assert "csv_url_en" in data assert "csv_url_de" in data assert "default_tax_rate" in data assert "delivery_method" in data def test_product_import_requires_csv_url( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test that product import requires at least one CSV URL""" # Set up: complete steps 1 and 2 first onboarding = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if not onboarding: onboarding = VendorOnboarding( vendor_id=test_vendor_with_vendor_user.id, status=OnboardingStatus.IN_PROGRESS.value, current_step=OnboardingStep.PRODUCT_IMPORT.value, ) db.add(onboarding) onboarding.step_company_profile_completed = True onboarding.step_letzshop_api_completed = True onboarding.current_step = OnboardingStep.PRODUCT_IMPORT.value db.commit() # Try to save without any CSV URL response = client.post( "/api/v1/vendor/onboarding/step/product-import", headers=vendor_user_headers, json={ "default_tax_rate": 17, "delivery_method": "package_delivery", "preorder_days": 1, }, ) # Should fail with validation error assert response.status_code == 422 @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingStep4API: """Test Step 4: Order Sync endpoints""" def test_order_sync_progress_endpoint( self, client, vendor_user_headers, test_vendor_with_vendor_user ): """Test getting order sync progress for non-existent job""" response = client.get( "/api/v1/vendor/onboarding/step/order-sync/progress/99999", headers=vendor_user_headers, ) assert response.status_code == 200 data = response.json() # Should return not_found status for non-existent job assert data["status"] == "not_found" assert data["job_id"] == 99999 @pytest.mark.integration @pytest.mark.api @pytest.mark.vendor class TestVendorOnboardingFlowAPI: """Test complete onboarding flow""" def test_completion_percentage_updates( self, client, vendor_user_headers, test_vendor_with_vendor_user, db ): """Test that completion percentage updates as steps are completed""" # Clear existing onboarding existing = ( db.query(VendorOnboarding) .filter(VendorOnboarding.vendor_id == test_vendor_with_vendor_user.id) .first() ) if existing: db.delete(existing) db.commit() # Check initial state response = client.get( "/api/v1/vendor/onboarding/status", headers=vendor_user_headers ) data = response.json() assert data["completion_percentage"] == 0 # Complete step 1 client.post( "/api/v1/vendor/onboarding/step/company-profile", headers=vendor_user_headers, json={ "default_language": "fr", "dashboard_language": "fr", }, ) # Check progress response = client.get( "/api/v1/vendor/onboarding/status", headers=vendor_user_headers ) data = response.json() assert data["completion_percentage"] == 25 # 1/4 = 25% assert data["completed_steps_count"] == 1