Files
WonderQ-Project/WonderQ-Admin/tests/test_home.py
duanshuwen fbf2c772a8 refactor: 清理废弃模块并重构管理端与全端代码
- 移除所有废弃的旧首页配置模块,包括destinationHero、demand相关、HomeExperience、vehicleService等表结构与代码,新增数据库迁移删除遗留表
- 重构管理端后台布局为标准RuoYi风格,新增Sidebar、Navbar、SettingsDrawer等组件,替换旧的过渡菜单实现
- 调整移动端响应断点为768px,更新布局相关测试用例,新增布局组件测试
- 删除OperationsTools发布/重置页面,移除/tools菜单入口,清理对应的API调用与测试代码
- 重构玩法模块编辑器:替换旧的图片手动输入框为图片上传组件,移除冗余的取消按钮
- 新增线索查询offset参数支持,完善查询参数处理逻辑
- 优化rbac菜单构建逻辑,新增可见性控制参数
- 修正管家编辑器提示文案,优化系统资源编辑器表单初始化逻辑
- 清理小程序端废弃的体验推荐组件与相关测试代码
- 更新文档与种子脚本,匹配新的API契约与使用说明
2026-08-26 23:24:28 +08:00

463 lines
15 KiB
Python

from datetime import datetime
import pytest
from fastapi.testclient import TestClient
from pydantic import ValidationError
from app.auth import require_admin
from app.database import get_db
from app.main import create_app
from app.models import (
AdminUser,
HomeTeamBuilding,
HomeWanfaRecommendation,
HomeWildArchive,
WanfaCategory,
WanfaRoute,
)
from app.schemas import HomeTeamBuildingCreate, HomeWanfaRecommendationCreate, HomeWildArchiveCreate
class FakeScalarResult:
def __init__(self, items):
self.items = items
def all(self):
return self.items
class FakeDb:
def __init__(self, *, items=None, items_by_model=None, scalar_values=None):
self.items = list(items or [])
self.items_by_model = items_by_model or {}
self.scalar_values = list(scalar_values or [])
self.added = []
self.deleted = []
self.committed = False
def scalars(self, statement):
entity = statement.column_descriptions[0].get("entity")
return FakeScalarResult(self.items_by_model.get(entity, self.items))
def scalar(self, _statement):
return self.scalar_values.pop(0) if self.scalar_values else None
def get(self, model, item_id):
candidates = self.items_by_model.get(model, self.items)
return next((item for item in candidates if isinstance(item, model) and item.id == item_id), None)
def add(self, item):
self.added.append(item)
self.items.append(item)
def delete(self, item):
self.deleted.append(item)
if item in self.items:
self.items.remove(item)
def flush(self):
for item in self.added:
if not getattr(item, "id", None):
item.id = "home-item-test-id"
def commit(self):
self.committed = True
def make_admin_user():
return AdminUser(
id="admin-test",
email="admin@example.test",
name="Admin",
role="admin",
passwordHash="not-used",
isActive=True,
)
def make_team(**overrides):
return HomeTeamBuilding(
id=overrides.get("id", "wild-challenge"),
tag=overrides.get("tag", "户外挑战"),
title=overrides.get("title", "山野挑战,共创极境"),
description=overrides.get("description", "洞穴、瀑降与协作,适合 10-30 人。"),
image=overrides.get("image", "https://example.test/team.jpg"),
demandKeyword=overrides.get("demandKeyword", "户外团建"),
detailSubtitle=overrides.get("detailSubtitle", "越过山丘,向来处去"),
detailParagraphs=overrides.get("detailParagraphs", ["真正的贵州,从未被写进攻略里的山野故事。", "我们用一次次出发,把团队重新带回自然。"]),
isActive=overrides.get("isActive", True),
sortOrder=overrides.get("sortOrder", 0),
createdAt=datetime(2026, 1, 1),
updatedAt=datetime(2026, 1, 2),
)
def make_archive(**overrides):
return HomeWildArchive(
id=overrides.get("id", "hundred-meter-descent"),
title=overrides.get("title", "百米自降"),
image=overrides.get("image", "https://example.test/archive.jpg"),
images=overrides.get("images", ["https://example.test/archive.jpg", "https://example.test/archive-2.jpg"]),
demandKeyword=overrides.get("demandKeyword", "悬崖瀑降"),
isActive=overrides.get("isActive", True),
sortOrder=overrides.get("sortOrder", 0),
createdAt=datetime(2026, 1, 1),
updatedAt=datetime(2026, 1, 2),
)
def make_wanfa_category(**overrides):
route = WanfaRoute(
id="family-water",
categoryId=overrides.get("id", "family-route"),
title="亲子玩水",
subtitle="贵州·轻松节奏与自然课堂",
image="https://example.test/family-water.jpg",
routeCount=4,
demandKeyword="亲子玩水",
sortOrder=0,
)
return WanfaCategory(
id=overrides.get("id", "family-route"),
label=overrides.get("label", "亲子路线"),
sortOrder=0,
routes=[route],
)
def make_wanfa_recommendation(category=None, **overrides):
category = category or make_wanfa_category()
return HomeWanfaRecommendation(
id=overrides.get("id", "recommendation-1"),
categoryId=category.id,
category=category,
isActive=overrides.get("isActive", True),
sortOrder=overrides.get("sortOrder", 0),
createdAt=datetime(2026, 1, 1),
updatedAt=datetime(2026, 1, 2),
)
def admin_app(fake_db):
app = create_app()
app.dependency_overrides[get_db] = lambda: fake_db
app.dependency_overrides[require_admin] = make_admin_user
return app
def test_home_wild_archive_schema_normalizes_detail_image_urls():
item = HomeWildArchiveCreate(
title=" 石龙洞 ",
image=" https://example.test/cover.jpg ",
images=[" https://example.test/one.jpg ", "https://example.test/two.jpg"],
demandKeyword=" 地心探险 ",
)
assert item.title == "石龙洞"
assert item.image == "https://example.test/cover.jpg"
assert item.images == ["https://example.test/one.jpg", "https://example.test/two.jpg"]
def test_home_team_building_schema_normalizes_detail_content():
item = HomeTeamBuildingCreate(
tag=" 户外挑战 ",
title=" 山野挑战,共创极境 ",
description=" 洞穴、瀑降与协作。 ",
image=" https://example.test/team.jpg ",
demandKeyword=" 户外团建 ",
detailSubtitle=" 越过山丘,向来处去 ",
detailParagraphs=[" 第一段 ", "", " 第二段 "],
)
assert item.detailSubtitle == "越过山丘,向来处去"
assert item.detailParagraphs == ["第一段", "第二段"]
def test_admin_home_team_create_appends_to_end():
fake_db = FakeDb(scalar_values=[2])
app = admin_app(fake_db)
try:
response = TestClient(app).post(
"/api/admin/home/team-buildings",
json={
"tag": " 团队协作 ",
"title": "峡谷溯溪,默契同行",
"description": "溯溪与分组协作,兼顾参与感与安全。",
"image": "https://example.test/team.jpg",
"demandKeyword": "峡谷团建",
"detailSubtitle": "并肩探索,共创默契",
"detailParagraphs": ["第一段正文", "第二段正文"],
},
)
finally:
app.dependency_overrides.clear()
assert response.status_code == 201
assert fake_db.added[0].tag == "团队协作"
assert fake_db.added[0].detailSubtitle == "并肩探索,共创默契"
assert fake_db.added[0].detailParagraphs == ["第一段正文", "第二段正文"]
assert fake_db.added[0].sortOrder == 3
assert fake_db.committed
def test_admin_home_wild_patch_updates_record():
archive = make_archive()
fake_db = FakeDb(items=[archive])
app = admin_app(fake_db)
try:
response = TestClient(app).patch(
"/api/admin/home/wild-archives/hundred-meter-descent",
json={"title": "百米自降体验", "isActive": False},
)
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json()["data"]["title"] == "百米自降体验"
assert response.json()["data"]["isActive"] is False
assert fake_db.committed
def test_admin_home_team_patch_updates_detail_content():
team = make_team()
fake_db = FakeDb(items=[team])
app = admin_app(fake_db)
try:
response = TestClient(app).patch(
"/api/admin/home/team-buildings/wild-challenge",
json={
"detailSubtitle": " 并肩探索,共创默契 ",
"detailParagraphs": [" 第一段正文 ", "", " 第二段正文 "],
},
)
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert team.detailSubtitle == "并肩探索,共创默契"
assert team.detailParagraphs == ["第一段正文", "第二段正文"]
assert fake_db.committed
def test_admin_home_wild_create_persists_detail_images():
fake_db = FakeDb(scalar_values=[0])
app = admin_app(fake_db)
try:
response = TestClient(app).post(
"/api/admin/home/wild-archives",
json={
"title": "石龙洞——客片案例",
"image": "https://example.test/cover.jpg",
"images": ["https://example.test/cover.jpg", "https://example.test/inside.jpg"],
"demandKeyword": "地心探险",
},
)
finally:
app.dependency_overrides.clear()
assert response.status_code == 201
assert fake_db.added[0].images == [
"https://example.test/cover.jpg",
"https://example.test/inside.jpg",
]
def test_home_wanfa_recommendation_schema_requires_category_id():
item = HomeWanfaRecommendationCreate(categoryId=" family-route ")
assert item.categoryId == "family-route"
def test_admin_home_wanfa_recommendation_create_links_existing_category():
category = make_wanfa_category()
fake_db = FakeDb(items=[category], scalar_values=[0])
app = admin_app(fake_db)
try:
response = TestClient(app).post(
"/api/admin/home/play-recommendations",
json={"categoryId": " family-route "},
)
finally:
app.dependency_overrides.clear()
assert response.status_code == 201
assert response.json()["data"]["categoryId"] == "family-route"
assert response.json()["data"]["categoryLabel"] == "亲子路线"
assert fake_db.added[0].categoryId == "family-route"
def test_public_home_places_active_wanfa_category_recommendations_in_experiences():
recommendation = make_wanfa_recommendation()
app = create_app()
fake_db = FakeDb(
items_by_model={
HomeTeamBuilding: [],
HomeWildArchive: [],
HomeWanfaRecommendation: [recommendation],
}
)
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
payload = response.json()["data"]
assert payload["experiences"] == [
{
"id": "recommendation-1",
"categoryId": "family-route",
"label": "亲子路线",
"routes": [
{
"id": "family-water",
"title": "亲子玩水",
"subtitle": "贵州·轻松节奏与自然课堂",
"image": "https://example.test/family-water.jpg",
"routeCount": 4,
"demandKeyword": "亲子玩水",
}
],
}
]
assert "playRecommendations" not in payload
def test_public_home_returns_rendering_fields_for_all_sections():
app = create_app()
fake_db = FakeDb(
items_by_model={
HomeTeamBuilding: [make_team()],
HomeWildArchive: [make_archive()],
}
)
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json() == {
"code": 200,
"msg": "success",
"data": {
"experiences": [],
"teamBuildings": [
{
"id": "wild-challenge",
"tag": "户外挑战",
"title": "山野挑战,共创极境",
"description": "洞穴、瀑降与协作,适合 10-30 人。",
"image": "https://example.test/team.jpg",
"demandKeyword": "户外团建",
}
],
"wildArchives": [
{
"id": "hundred-meter-descent",
"title": "百米自降",
"image": "https://example.test/archive.jpg",
"demandKeyword": "悬崖瀑降",
"photoCount": 2,
}
],
},
}
def test_public_wild_archive_list_returns_photo_count():
archive = make_archive()
app = create_app()
fake_db = FakeDb(items_by_model={HomeWildArchive: [archive]})
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home/wild-archives")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json()["data"]["items"][0] == {
"id": "hundred-meter-descent",
"title": "百米自降",
"image": "https://example.test/archive.jpg",
"demandKeyword": "悬崖瀑降",
"photoCount": 2,
}
def test_public_wild_archive_detail_returns_all_images():
archive = make_archive()
app = create_app()
fake_db = FakeDb(scalar_values=[archive])
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home/wild-archives/hundred-meter-descent")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json()["data"]["title"] == "百米自降"
assert response.json()["data"]["images"] == [
"https://example.test/archive.jpg",
"https://example.test/archive-2.jpg",
]
def test_public_team_building_detail_returns_long_form_content():
team = make_team()
app = create_app()
fake_db = FakeDb(scalar_values=[team])
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home/team-buildings/wild-challenge")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json() == {
"code": 200,
"msg": "success",
"data": {
"id": "wild-challenge",
"tag": "户外挑战",
"title": "山野挑战,共创极境",
"description": "洞穴、瀑降与协作,适合 10-30 人。",
"image": "https://example.test/team.jpg",
"demandKeyword": "户外团建",
"detailSubtitle": "越过山丘,向来处去",
"detailParagraphs": [
"真正的贵州,从未被写进攻略里的山野故事。",
"我们用一次次出发,把团队重新带回自然。",
],
},
}
def test_public_team_building_detail_returns_not_found_for_missing_item():
app = create_app()
app.dependency_overrides[get_db] = lambda: FakeDb(scalar_values=[None])
try:
response = TestClient(app).get("/api/public/home/team-buildings/missing")
finally:
app.dependency_overrides.clear()
assert response.status_code == 404
assert response.json()["msg"] == "团队共创不存在"
def test_public_team_building_detail_falls_back_to_legacy_description():
team = make_team(detailSubtitle="", detailParagraphs=[])
app = create_app()
fake_db = FakeDb(scalar_values=[team])
app.dependency_overrides[get_db] = lambda: fake_db
try:
response = TestClient(app).get("/api/public/home/team-buildings/wild-challenge")
finally:
app.dependency_overrides.clear()
assert response.status_code == 200
assert response.json()["data"]["detailSubtitle"] == team.description
assert response.json()["data"]["detailParagraphs"] == [team.description]