# ============================================================================= # 企微IT智能服务台 — H5 摇人功能测试 # ============================================================================= # 测试覆盖: # 1. 摇人成功(新建会话 + 举手标记 + 趣味话术返回) # 2. 摇人成功(已有会话 + 更新举手标记) # 3. 缺少 employee_id 请求失败 # 4. 获取当前会话 # 5. H5 发送消息 # 6. 审批链接获取 # 7. 软件下载列表获取 # ============================================================================= import pytest import pytest_asyncio from unittest.mock import AsyncMock, patch from app.models.conversation import Conversation from app.models.funny_phrase import FunnyPhrase from tests.conftest import create_test_conversation, MockRedis class TestShakeEndpoint: """测试摇人 API 端点。""" @pytest.mark.asyncio async def test_shake_creates_new_conversation(self, client, db_session): """验证摇人时如果没有活跃会话则创建新会话。""" # 先添加趣味话术 phrase = FunnyPhrase(scene="shake", content="摇人话术测试", tone="亲切", sort_order=1) db_session.add(phrase) await db_session.flush() response = await client.post( "/h5/conversations/current/shake", json={"employee_id": "shake_new_user", "employee_name": "测试员工"}, ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"]["conversation"]["tags"]["hand_raise"] is True assert data["data"]["funny_phrase"] != "" @pytest.mark.asyncio async def test_shake_updates_existing_conversation(self, client, db_session): """验证摇人时如果已有活跃会话则更新举手标记。""" conv = create_test_conversation( employee_id="shake_existing_user", status="queued", tags={}, ) db_session.add(conv) await db_session.flush() # 添加话术 phrase = FunnyPhrase(scene="shake", content="更新摇人话术", tone="亲切", sort_order=1) db_session.add(phrase) await db_session.flush() response = await client.post( "/h5/conversations/current/shake", json={"employee_id": "shake_existing_user", "employee_name": "已有用户"}, ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"]["conversation"]["tags"]["hand_raise"] is True @pytest.mark.asyncio async def test_shake_returns_funny_phrase(self, client, db_session): """验证摇人返回趣味话术。""" phrase = FunnyPhrase(scene="shake", content="测试趣味话术内容", tone="亲切", sort_order=1) db_session.add(phrase) await db_session.flush() response = await client.post( "/h5/conversations/current/shake", json={"employee_id": "phrase_test_user", "employee_name": "话术测试"}, ) data = response.json() assert data["data"]["funny_phrase"] != "" class TestH5CurrentConversation: """测试 H5 获取当前会话。""" @pytest.mark.asyncio async def test_get_current_conversation_exists(self, client, db_session, mock_redis): """验证获取当前活跃会话。""" # 预设 Bearer Token(替代旧的 X-Employee-Id 头) await mock_redis.setex("employee:token:h5_current_token", 28800, "h5_current_user") conv = create_test_conversation(employee_id="h5_current_user", status="queued") db_session.add(conv) await db_session.flush() response = await client.get( "/h5/conversations/current", headers={"Authorization": "Bearer h5_current_token"}, ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"] is not None @pytest.mark.asyncio async def test_get_current_conversation_not_found(self, client, db_session, mock_redis): """验证无活跃会话时返回空数据。""" # 预设 Bearer Token await mock_redis.setex("employee:token:no_conv_token", 28800, "no_conversation_user") response = await client.get( "/h5/conversations/current", headers={"Authorization": "Bearer no_conv_token"}, ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"] is None @pytest.mark.asyncio async def test_get_current_conversation_no_employee_id(self, client, db_session): """验证缺少员工ID时返回未授权错误。""" response = await client.get("/h5/conversations/current") assert response.status_code == 200 data = response.json() assert data["code"] != 0 # 应返回错误码 class TestH5SendMessage: """测试 H5 发送消息。""" @pytest.mark.asyncio async def test_send_message_creates_conversation(self, client, db_session, mock_redis): """验证发送消息时自动创建会话。""" # 预设 Bearer Token await mock_redis.setex("employee:token:h5_msg_token", 28800, "h5_msg_user") response = await client.post( "/h5/conversations/current/messages", json={"content": "VPN连不上了"}, headers={"Authorization": "Bearer h5_msg_token"}, ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"]["content"] == "VPN连不上了" @pytest.mark.asyncio async def test_send_message_empty_content(self, client, db_session, mock_redis): """验证空消息内容返回错误。""" # 预设 Bearer Token await mock_redis.setex("employee:token:empty_msg_token", 28800, "empty_msg_user") response = await client.post( "/h5/conversations/current/messages", json={"content": ""}, headers={"Authorization": "Bearer empty_msg_token"}, ) data = response.json() assert data["code"] != 0 class TestApprovalLinks: """测试审批链接获取。""" @pytest.mark.asyncio async def test_get_approval_links(self, client, seeded_db): """验证获取审批链接列表。""" response = await client.get("/h5/approval-links") assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert len(data["data"]["items"]) > 0 @pytest.mark.asyncio async def test_get_approval_links_by_category(self, client, seeded_db): """验证按分类过滤审批链接。""" response = await client.get("/h5/approval-links?category=IT") assert response.status_code == 200 data = response.json() assert data["code"] == 0 for item in data["data"]["items"]: assert item["category"] == "IT" class TestSoftwareDownloads: """测试软件下载列表。""" @pytest.mark.asyncio async def test_get_software_downloads(self, client, seeded_db): """验证获取软件下载列表。""" response = await client.get("/h5/software-downloads") assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert len(data["data"]["items"]) > 0 @pytest.mark.asyncio async def test_get_software_downloads_by_category(self, client, seeded_db): """验证按分类过滤软件下载。""" response = await client.get("/h5/software-downloads?category=办公") assert response.status_code == 200 data = response.json() assert data["code"] == 0 for item in data["data"]["items"]: assert item["category"] == "办公"