Files
personal-progress-monitor/tests/test_charts.py
MobKBK ff10e7f065 fix: 折线图纵轴优化——默认约80%头空间、取整到nice刻度,支持手动设置纵轴上限
- 纵轴自动刻度改为精细步进(1/1.5/2/2.5/3/4/5/6/8/10),数据最大值落在约80%处
- ChartInput 新增 yMax 字段(JSON 存储、可拓展),图表弹窗新增「纵轴上限」输入
- 新增 yMax 往返测试
2026-09-04 15:07:10 +08:00

79 lines
3.7 KiB
Python

from datetime import date
from app.models import ChartInput, DailyRecordInput, MetricValue, TaskInput
from app.repository import ConflictError, JsonRepository
def _task(repo):
return repo.create_task(TaskInput.model_validate({
"name": "复盘任务",
"metrics": [
{"name": "完成", "kind": "checkin", "period": "day"},
{"name": "数量", "kind": "quantity", "period": "day"},
],
}))
def test_chart_crud_and_conflict(tmp_path):
repo = JsonRepository(tmp_path)
chart = repo.create_chart(ChartInput(title="趋势"))
assert repo.list_charts()["items"][0]["chartId"] == chart["chartId"]
updated = repo.update_chart(chart["chartId"], ChartInput(title="新趋势"), chart["version"])
assert updated["version"] == 2
try:
repo.update_chart(chart["chartId"], ChartInput(title="冲突"), chart["version"])
except ConflictError:
pass
else:
raise AssertionError("expected chart version conflict")
assert repo.delete_chart(chart["chartId"])["deleted"] is True
def test_chart_yMax_roundtrip(tmp_path):
repo = JsonRepository(tmp_path)
bounded = repo.create_chart(ChartInput(title="带上限", yMax=10))
assert repo.get_chart(bounded["chartId"])["yMax"] == 10
auto = repo.create_chart(ChartInput(title="自动"))
assert repo.get_chart(auto["chartId"])["yMax"] is None
def test_chart_data_modes_and_continuous_points(tmp_path):
repo = JsonRepository(tmp_path)
task = _task(repo)
checkin_id, quantity_id = [metric["metricId"] for metric in task["metrics"]]
repo.upsert_daily(task["taskId"], date(2026, 8, 2), DailyRecordInput(values=[MetricValue(metricId=checkin_id, value=1), MetricValue(metricId=quantity_id, value=3)], note="完成"))
repo.upsert_daily(task["taskId"], date(2026, 8, 4), DailyRecordInput(values=[MetricValue(metricId=quantity_id, value=2)]))
done = repo.create_chart(ChartInput(title="完成数", days=7))
metric = repo.create_chart(ChartInput(title="数量", taskId=task["taskId"], metricId=quantity_id, days=7))
for result in (repo.chart_data(done["chartId"], date(2026, 8, 4)), repo.chart_data(metric["chartId"], date(2026, 8, 4))):
assert len(result["points"]) == 7
assert [point["date"] for point in result["points"]] == sorted(point["date"] for point in result["points"])
done_points = {point["date"]: point["value"] for point in repo.chart_data(done["chartId"], date(2026, 8, 4))["points"]}
metric_points = {point["date"]: point["value"] for point in repo.chart_data(metric["chartId"], date(2026, 8, 4))["points"]}
assert done_points["2026-08-03"] == 0 and done_points["2026-08-04"] == 1
assert metric_points["2026-08-02"] == 3 and metric_points["2026-08-03"] == 0
def test_review_notes_skips_empty_and_resolves_deleted_task(tmp_path):
repo = JsonRepository(tmp_path)
task = _task(repo)
repo.upsert_daily(task["taskId"], date(2026, 8, 1), DailyRecordInput(note="心得"))
repo.upsert_daily(task["taskId"], date(2026, 8, 2), DailyRecordInput())
repo.soft_delete_task(task["taskId"], task["version"])
result = repo.review_notes(date(2026, 8, 1), date(2026, 8, 2))
assert [day["date"] for day in result["days"]] == ["2026-08-01"]
assert result["days"][0]["records"][0]["taskName"] == "已删除任务"
def test_export_import_charts(tmp_path):
repo = JsonRepository(tmp_path)
repo.create_chart(ChartInput(title="备份图表"))
exported = repo.export_all()
assert len(exported["charts"]) == 1
target = JsonRepository(tmp_path / "target")
target.import_all(exported)
assert target.stats()["chartCount"] == 1
legacy = {key: value for key, value in exported.items() if key != "charts"}
target.import_all(legacy)
assert target.stats()["chartCount"] == 0