import pytest from httpx import AsyncClient from unittest.mock import patch, AsyncMock from app.models.customer import Conversation, Message from app.models.quotation import Quotation, QuotationItem from app.models.user import Product from datetime import datetime class TestTranslateAPI: async def test_translate_unauthorized(self, client: AsyncClient): response = await client.post( "/api/v1/translate", json={"text": "Hello", "target_lang": "zh"}, ) assert response.status_code == 401 async def test_translate_success(self, client: AsyncClient, auth_headers): with patch("app.services.translation.TranslationService.translate") as mock: mock.return_value = { "translated_text": "你好", "source_lang": "en", "provider_used": "mock", "from_cache": False, } response = await client.post( "/api/v1/translate", headers=auth_headers, json={"text": "Hello", "target_lang": "zh"}, ) assert response.status_code == 200 data = response.json() assert data["translated_text"] == "你好" async def test_translate_with_context(self, client: AsyncClient, auth_headers): with patch("app.services.translation.TranslationService.translate") as mock: mock.return_value = { "translated_text": "FOB 上海 价格", "source_lang": "en", "provider_used": "mock", } response = await client.post( "/api/v1/translate", headers=auth_headers, json={"text": "FOB Shanghai price", "target_lang": "zh", "context": "trade"}, ) assert response.status_code == 200 class TestReplyAPI: async def test_reply_unauthorized(self, client: AsyncClient): response = await client.post( "/api/v1/translate/reply", json={"inquiry": "How much?", "tone": "professional"}, ) assert response.status_code == 401 async def test_reply_success(self, client: AsyncClient, auth_headers): with patch("app.services.translation.TranslationService.generate_reply") as mock: mock.return_value = [ {"reply": "Thank you for your inquiry.", "tone": "professional", "provider": "mock"}, {"reply": "Thanks for reaching out!", "tone": "friendly", "provider": "mock"}, ] response = await client.post( "/api/v1/translate/reply", headers=auth_headers, json={"inquiry": "How much for 500 units?", "tone": "professional", "count": 2}, ) assert response.status_code == 200 data = response.json() assert len(data["suggestions"]) == 2 assert data["count"] == 2 async def test_reply_with_context(self, client: AsyncClient, auth_headers): with patch("app.services.translation.TranslationService.generate_reply") as mock: mock.return_value = [{"reply": "Our price is $10/unit.", "tone": "professional", "provider": "mock"}] response = await client.post( "/api/v1/translate/reply", headers=auth_headers, json={ "inquiry": "Price?", "tone": "professional", "count": 1, "context": {"product": "Widget X", "price": "$10"}, }, ) assert response.status_code == 200 class TestExtractAPI: async def test_extract_unauthorized(self, client: AsyncClient): response = await client.post( "/api/v1/translate/extract", json={"text": "I want 500pcs of red widgets FOB Shanghai", "extract_type": "inquiry"}, ) assert response.status_code == 401 async def test_extract_success(self, client: AsyncClient, auth_headers): with patch("app.services.translation.TranslationService.extract_info") as mock: mock.return_value = { "intent": "purchase", "product_interest": "widgets", "quantity": "500", } response = await client.post( "/api/v1/translate/extract", headers=auth_headers, json={"text": "I want 500pcs of red widgets FOB Shanghai", "extract_type": "inquiry"}, ) assert response.status_code == 200 data = response.json() assert "extracted" in data class TestTTSAPI: async def test_tts_get_unauthorized(self, client: AsyncClient): response = await client.get("/api/v1/translate/tts?text=hello&lang=en") assert response.status_code == 401 async def test_tts_get_empty_text(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/translate/tts?text=&lang=en", headers=auth_headers) assert response.status_code == 400 class TestMarketingAPI: async def test_marketing_unauthorized(self, client: AsyncClient): response = await client.post( "/api/v1/marketing/generate", json={"product_name": "Widget", "description": "A great widget", "target": "US buyers"}, ) assert response.status_code == 401 async def test_marketing_success(self, client: AsyncClient, auth_headers): with patch("app.services.marketing.MarketingService.generate") as mock: mock.return_value = [ {"content": "Buy our widget!", "style": "professional", "provider": "mock"}, ] response = await client.post( "/api/v1/marketing/generate", headers=auth_headers, json={ "product_name": "Widget X", "description": "High quality widget", "category": "tools", "target": "US importers", "style": "professional", "count": 1, }, ) assert response.status_code == 200 data = response.json() assert data["count"] >= 1 assert "results" in data async def test_marketing_keywords(self, client: AsyncClient, auth_headers): with patch("app.services.marketing.MarketingService.generate_keywords") as mock: mock.return_value = ["widget", "tool", "quality"] response = await client.post( "/api/v1/marketing/keywords", headers=auth_headers, json={"product_name": "Widget", "description": "A widget", "count": 5}, ) assert response.status_code == 200 assert "keywords" in response.json() class TestProductAPI: async def test_create_product(self, client: AsyncClient, auth_headers): response = await client.post( "/api/v1/products", headers=auth_headers, json={ "name": "Test Product", "description": "A test product", "category": "electronics", "price": "10.50", "price_unit": "USD", }, ) assert response.status_code == 200 data = response.json() assert data["name"] == "Test Product" async def test_list_products(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/products", headers=auth_headers) assert response.status_code == 200 data = response.json() assert "items" in data async def test_update_product(self, client: AsyncClient, auth_headers, db_session, test_user): product = Product( user_id=test_user.id, name="Old Name", category="tools", is_active=True, ) db_session.add(product) await db_session.commit() response = await client.patch( f"/api/v1/products/{product.id}", headers=auth_headers, json={"name": "New Name", "price": "20.00"}, ) assert response.status_code == 200 assert response.json()["name"] == "New Name" async def test_delete_product(self, client: AsyncClient, auth_headers, db_session, test_user): product = Product(user_id=test_user.id, name="To Delete") db_session.add(product) await db_session.commit() pid = product.id response = await client.delete(f"/api/v1/products/{pid}", headers=auth_headers) assert response.status_code == 200 response = await client.get(f"/api/v1/products/{pid}", headers=auth_headers) assert response.status_code == 404 class TestQuotationAPI: async def test_create_quotation(self, client: AsyncClient, auth_headers, db_session, test_user): from app.models.customer import Customer customer = Customer(user_id=test_user.id, name="Test Buyer") db_session.add(customer) await db_session.commit() response = await client.post( "/api/v1/quotations", headers=auth_headers, json={ "customer_id": str(customer.id), "title": "Test Quote", "items": [ {"product_name": "Widget", "quantity": 100, "unit_price": 10.0}, ], "currency": "USD", "payment_terms": "T/T", }, ) assert response.status_code == 200 data = response.json() assert data["title"] == "Test Quote" assert len(data["items"]) == 1 async def test_list_quotations(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/quotations", headers=auth_headers) assert response.status_code == 200 assert "items" in response.json() async def test_quotation_pdf_not_found(self, client: AsyncClient, auth_headers): import uuid response = await client.get(f"/api/v1/quotations/{uuid.uuid4()}/pdf", headers=auth_headers) assert response.status_code == 404 async def test_quotation_status_update(self, client: AsyncClient, auth_headers, db_session, test_user): from app.models.customer import Customer customer = Customer(user_id=test_user.id, name="Status Test Buyer") db_session.add(customer) await db_session.commit() q = Quotation(user_id=test_user.id, customer_id=customer.id, title="Status Test", status="draft") db_session.add(q) await db_session.commit() response = await client.patch( f"/api/v1/quotations/{q.id}/status", headers=auth_headers, json={"status": "sent"}, ) assert response.status_code == 200 assert response.json()["status"] == "sent" class TestAnalyticsAPI: async def test_overview(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/analytics/overview", headers=auth_headers) assert response.status_code == 200 data = response.json() assert "customers" in data assert "translations" in data assert "quotations" in data assert "messages" in data assert "marketing" in data async def test_customer_analytics(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/analytics/customers", headers=auth_headers) assert response.status_code == 200 async def test_marketing_analytics(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/analytics/marketing", headers=auth_headers) assert response.status_code == 200 data = response.json() assert "total_events" in data class TestOnboardingAPI: async def test_onboarding_status(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/onboarding/status", headers=auth_headers) assert response.status_code == 200 data = response.json() assert "completed" in data assert "product_count" in data async def test_onboarding_create_product(self, client: AsyncClient, auth_headers): with patch("app.services.onboarding.OnboardingService.create_product") as mock: mock.return_value = { "id": "mock-id", "name": "Onboarded Product", "marketing_contents": [], "keywords": [], } response = await client.post( "/api/v1/onboarding/product", headers=auth_headers, json={ "name": "New Product", "description": "Desc", "category": "tools", "target": "US buyers", }, ) assert response.status_code == 200 assert response.json()["name"] == "Onboarded Product" class TestExportAPI: async def test_export_customers_csv(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/customers/export/csv", headers=auth_headers) assert response.status_code == 200 assert response.headers["content-type"] == "text/csv" assert "customers.csv" in response.headers["content-disposition"] async def test_export_quotations_csv(self, client: AsyncClient, auth_headers): response = await client.get("/api/v1/quotations/export/csv", headers=auth_headers) assert response.status_code == 200 assert response.headers["content-type"] == "text/csv"