test: 补充 WO-11 页面错误兜底测试

This commit is contained in:
meijiali
2026-07-03 17:59:13 +08:00
parent f91d2272d8
commit d6f0f7c1b0
2 changed files with 116 additions and 0 deletions
+20
View File
@@ -978,6 +978,26 @@ fix: 修复页面刷新和按钮点击的 500 错误
- 用户需要提供或复现最容易触发 500 的页面 URL 与按钮名称;如果无法提供,则开发时先从当前浏览器打开的任务详情页开始排查。
完成记录:
- 完成日期:2026-07-03
- 相关改动:
- 补充路由回归测试,覆盖任务详情页、热点报告页、内容详情页、导出接口在数据库 I/O error 下的 503 兜底。
- 补充缺失任务、缺失热点、缺失内容页面的 404 兜底测试,确保不是裸 500。
- 核查当前实现已有 `OperationalError` / `SQLAlchemyError` 全局 handlerAPI 返回 503 JSON,HTML 页面返回数据库不可用友好页。
- 验证命令:
- `docker cp tests/. hot-comments-tool-app-1:/app/tests/`
- `docker exec hot-comments-tool-app-1 sh -lc 'python -m pytest /app/tests/integration/test_routes.py -q'`
- 验证结果:
- `19 passed, 1 warning`
- 验收结论:
- 已知高频页面路由和导出入口在数据库 I/O error 下不会返回裸 `Internal Server Error`
- 缺失任务、热点、内容不会返回 500。
- 服务端日志仍保留异常信息,页面/API 返回可理解错误。
- 遗留问题:
- 轮询接口偶发 503 时,前端当前只是静默返回,用户看不到“最近一次同步失败”提示;归入 WO-19 / WO-13 前端提示优化。
- 当前本机 Python `.venv` 仍未完成依赖安装,本轮测试通过运行容器执行。
### WO-12 导出 Markdown / CSV 点击失效修复
优先级:P0
+96
View File
@@ -384,6 +384,102 @@ def test_index_page_shows_database_error_state_when_database_has_io_error(monkey
assert "请先保留 data 目录" in response.text
def test_task_detail_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
def broken_get_task(_session, _task_id):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.get_task", broken_get_task)
with make_test_client() as (client, _engine):
response = client.get("/tasks/task-io-error")
assert response.status_code == 503
assert "数据库暂时不可用" in response.text
assert "请先保留 data 目录" in response.text
def test_hotspot_report_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
def broken_get_task(_session, _task_id):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.get_task", broken_get_task)
with make_test_client() as (client, engine):
from sqlalchemy.orm import Session
with Session(engine) as session:
session.add(Task(id="task-hot-io", platform="xiaohongshu", status="success"))
session.add(Hotspot(id="hot-io", task_id="task-hot-io", platform="xiaohongshu", title="热点", rank=1, raw_data="{}"))
session.commit()
response = client.get("/hotspots/hot-io/report")
assert response.status_code == 503
assert "数据库暂时不可用" in response.text
def test_item_detail_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
def broken_get_task(_session, _task_id):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.get_task", broken_get_task)
with make_test_client() as (client, engine):
from sqlalchemy.orm import Session
with Session(engine) as session:
session.add(Task(id="task-item-io", platform="xiaohongshu", status="success"))
session.add(Hotspot(id="hot-item-io", task_id="task-item-io", platform="xiaohongshu", title="热点", rank=1, raw_data="{}"))
session.add(
ContentItem(
id="item-io",
task_id="task-item-io",
hotspot_id="hot-item-io",
platform="xiaohongshu",
source_item_id="item-io-source",
item_type="note",
status="success",
raw_data="{}",
)
)
session.commit()
response = client.get("/items/item-io")
assert response.status_code == 503
assert "数据库暂时不可用" in response.text
def test_export_route_returns_service_unavailable_when_database_has_io_error(monkeypatch):
def broken_export(_session, _item_id):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.export_item_comments_csv", broken_export)
with make_test_client() as (client, _engine):
response = client.get("/api/export/items/item-io/comments.csv")
assert response.status_code == 503
assert response.json()["detail"] == "数据库暂时不可用,请稍后重试或联系维护者恢复数据。"
def test_missing_html_pages_render_friendly_not_found_page():
with make_test_client() as (client, _engine):
task_response = client.get("/tasks/missing-task")
hotspot_response = client.get("/hotspots/missing-hotspot/report")
item_response = client.get("/items/missing-item")
assert task_response.status_code == 404
assert "任务不存在" in task_response.text
assert "Internal Server Error" not in task_response.text
assert hotspot_response.status_code == 404
assert "热点不存在" in hotspot_response.text
assert "Internal Server Error" not in hotspot_response.text
assert item_response.status_code == 404
assert "内容条目不存在" in item_response.text
assert "Internal Server Error" not in item_response.text
def test_task_api_includes_progress_counts_stage_and_demo_flag():
with make_test_client() as (client, engine):
seed_result_data(engine)