Files

219 lines
7.8 KiB
Python
Raw Permalink Normal View History

# =============================================================================
# 企微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"] == "办公"