Project.Fengling.QoderVersion/tests/test_sse_integration.py
sam d88ec60ef4 feat(marketing): 扩展营销码支持品类信息并完善通知机制
- 在MarketingCode聚合中新增品类ID和品类名称字段,完善产品信息结构
- 迁移生成营销码命令,支持传入品类ID和品类名称参数
- 积分发放失败时发送积分获得失败通知集成事件
- 新增通知发送及积分失败通知的集成事件处理器,使用SSE推送通知
- 在积分相关集成事件处理器中添加发送积分变动通知功能
- 移除Notification聚合,相关数据库表删除
- 新增分页结果类型PagedResult,支持营销码查询分页返回
- 营销码查询支持分页参数,返回分页结果数据
2026-02-13 19:00:06 +08:00

230 lines
7.7 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
SSE通知功能集成测试脚本
验证前端页面是否能正确接收和处理积分变动通知
"""
import requests
import json
import time
from datetime import datetime
# 配置
BASE_URL = "http://localhost:5000"
ADMIN_EMAIL = "admin@example.com"
ADMIN_PASSWORD = "Admin123!"
def log_step(step_num, description, status="INFO"):
"""记录测试步骤"""
timestamp = datetime.now().strftime("%H:%M:%S")
status_icon = {
"PASS": "",
"FAIL": "",
"INFO": "",
"WARN": "⚠️"
}
print(f"[{timestamp}] {status_icon.get(status, '')} 步骤 {step_num}: {description}")
def get_admin_token():
"""获取管理员token"""
try:
response = requests.post(
f"{BASE_URL}/api/admins/login",
json={
"email": ADMIN_EMAIL,
"password": ADMIN_PASSWORD
}
)
if response.status_code == 200:
data = response.json()
return data.get('data', {}).get('token')
return None
except Exception as e:
print(f"获取token失败: {e}")
return None
def create_test_member(admin_token):
"""创建测试会员"""
try:
response = requests.post(
f"{BASE_URL}/api/members",
headers={"Authorization": f"Bearer {admin_token}"},
json={
"phone": f"13800138{int(time.time()) % 10000:04d}",
"nickname": f"测试用户{int(time.time()) % 1000}",
"initialPoints": 1000
}
)
if response.status_code == 200:
data = response.json()
member_id = data.get('data', {}).get('id')
log_step(1, f"创建测试会员成功: {member_id}", "PASS")
return member_id
else:
log_step(1, f"创建测试会员失败: {response.text}", "FAIL")
return None
except Exception as e:
log_step(1, f"创建测试会员异常: {e}", "FAIL")
return None
def get_member_token(member_id):
"""模拟会员登录获取token"""
try:
# 这里简化处理,实际应该有会员登录接口
# 暂时返回None因为我们主要测试SSE通知机制
log_step(2, "获取会员token (简化处理)", "INFO")
return "test_member_token"
except Exception as e:
log_step(2, f"获取会员token失败: {e}", "FAIL")
return None
def trigger_points_event(admin_token, member_id, event_type, amount):
"""触发积分事件"""
try:
event_mapping = {
"earned": "PointsEarnedSuccess",
"consumed": "PointsConsumed",
"expired": "PointsExpired",
"refunded": "PointsRefunded"
}
event_data = {
"memberId": member_id,
"amount": amount,
"relatedId": f"test_{int(time.time())}",
"source": "测试系统"
}
if event_type == "consumed":
event_data["reason"] = "测试消费"
event_data["orderId"] = f"order_{int(time.time())}"
response = requests.post(
f"{BASE_URL}/api/test/trigger-points-event",
headers={"Authorization": f"Bearer {admin_token}"},
json={
"eventType": event_mapping[event_type],
"eventData": event_data
}
)
if response.status_code == 200:
log_step(3, f"触发积分{event_type}事件成功: {amount}积分", "PASS")
return True
else:
# 如果测试接口不存在尝试直接调用积分API
log_step(3, f"触发积分{event_type}事件失败,尝试备用方案", "WARN")
return trigger_points_via_api(admin_token, member_id, event_type, amount)
except Exception as e:
log_step(3, f"触发积分事件异常: {e}", "FAIL")
return False
def trigger_points_via_api(admin_token, member_id, event_type, amount):
"""通过API触发积分变动"""
try:
if event_type == "earned":
# 通过营销码扫码获得积分
response = requests.post(
f"{BASE_URL}/api/marketing-codes/mock-scan",
headers={"Authorization": f"Bearer {admin_token}"},
json={
"memberId": member_id,
"points": amount
}
)
elif event_type == "consumed":
# 通过创建兑换订单消费积分
response = requests.post(
f"{BASE_URL}/api/redemption-orders/mock-consume",
headers={"Authorization": f"Bearer {admin_token}"},
json={
"memberId": member_id,
"points": amount,
"reason": "测试消费"
}
)
else:
log_step(3, f"暂不支持的事件类型: {event_type}", "WARN")
return True
if response.status_code in [200, 201]:
log_step(3, f"通过API触发积分{event_type}成功: {amount}积分", "PASS")
return True
else:
log_step(3, f"通过API触发积分{event_type}失败: {response.text}", "FAIL")
return False
except Exception as e:
log_step(3, f"通过API触发积分事件异常: {e}", "FAIL")
return False
def verify_frontend_updates():
"""验证前端页面更新(模拟)"""
log_step(4, "验证前端SSE通知接收", "INFO")
print(" 请在前端页面观察以下变化:")
print(" - 首页: 积分余额应该自动更新")
print(" - 积分明细: 应该显示新的积分记录")
print(" - 个人中心: 积分信息应该同步更新")
print(" - 购物车/结算页面: 可用积分应该更新")
print(" - 通知气泡: 应该显示积分变动提醒")
input(" 手动验证完成后按回车继续...")
def test_sse_connection():
"""测试SSE连接"""
log_step(5, "测试SSE连接建立", "INFO")
print(" 请在浏览器开发者工具中检查:")
print(" - Network标签页应该显示到/api/notifications/sse的连接")
print(" - 连接状态应该是CONNECTED")
print(" - 应该定期收到心跳消息")
input(" 连接验证完成后按回车继续...")
def main():
"""主测试流程"""
print("=" * 60)
print("SSE通知功能集成测试")
print("=" * 60)
# 步骤1: 获取管理员权限
log_step(0, "获取管理员权限")
admin_token = get_admin_token()
if not admin_token:
log_step(0, "无法获取管理员权限,测试终止", "FAIL")
return
# 步骤2: 创建测试会员
member_id = create_test_member(admin_token)
if not member_id:
return
# 步骤3: 测试各种积分事件
events_to_test = [
("earned", 100),
("consumed", 50),
("earned", 200),
("expired", 10)
]
for event_type, amount in events_to_test:
print(f"\n--- 测试积分{event_type}事件 ---")
success = trigger_points_event(admin_token, member_id, event_type, amount)
if success:
# 等待一段时间让前端处理通知
time.sleep(3)
verify_frontend_updates()
else:
log_step(3, f"积分{event_type}事件测试失败", "FAIL")
# 步骤4: 测试SSE连接
print(f"\n--- SSE连接测试 ---")
test_sse_connection()
# 步骤5: 总结
print("\n" + "=" * 60)
print("测试完成!")
print("请检查前端页面是否正确显示了所有积分变动通知")
print("确保通知气泡正常显示且页面数据及时更新")
print("=" * 60)
if __name__ == "__main__":
main()