feat: show tasks completed today
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
from datetime import UTC, datetime
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
@@ -83,8 +84,17 @@ def test_task_can_be_updated_completed_and_soft_deleted(client):
|
||||
assert updated.status_code == 200
|
||||
assert updated.json()["title"] == "新标题"
|
||||
assert updated.json()["completed"] is True
|
||||
assert updated.json()["completed_at"] is not None
|
||||
assert updated.json()["version"] == 2
|
||||
|
||||
reopened = client.patch(
|
||||
f"/api/v1/tasks/{task['id']}",
|
||||
json={"completed": False, "version": updated.json()["version"]},
|
||||
)
|
||||
assert reopened.status_code == 200
|
||||
assert reopened.json()["completed"] is False
|
||||
assert reopened.json()["completed_at"] is None
|
||||
|
||||
conflict = client.patch(
|
||||
f"/api/v1/tasks/{task['id']}",
|
||||
json={"title": "冲突标题", "version": task["version"]},
|
||||
@@ -119,6 +129,105 @@ def test_reorder_tasks_persists_top_level_and_subtask_order(client):
|
||||
assert [task["title"] for task in listed[1]["subtasks"]] == ["子任务 B", "子任务 A"]
|
||||
|
||||
|
||||
def test_today_list_includes_tasks_completed_today_even_if_due_earlier(client, monkeypatch):
|
||||
client = initialized_client(client)
|
||||
inbox = client.get("/api/v1/lists").json()[0]
|
||||
overdue = client.post(
|
||||
"/api/v1/tasks",
|
||||
json={"title": "昨天截止今天完成", "list_id": inbox["id"], "due_at": "2026-09-14T02:00:00Z"},
|
||||
).json()
|
||||
today_due = client.post(
|
||||
"/api/v1/tasks",
|
||||
json={"title": "今天截止今天完成", "list_id": inbox["id"], "due_at": "2026-09-15T02:00:00Z"},
|
||||
).json()
|
||||
client.post(
|
||||
"/api/v1/tasks",
|
||||
json={"title": "今天未完成", "list_id": inbox["id"], "due_at": "2026-09-15T10:00:00Z"},
|
||||
).json()
|
||||
|
||||
completed_at = datetime(2026, 9, 15, 3, 30, tzinfo=UTC)
|
||||
monkeypatch.setattr("backend.recurrence_service.utcnow", lambda: completed_at)
|
||||
monkeypatch.setattr("backend.main.utcnow", lambda: completed_at)
|
||||
|
||||
completed_overdue = client.patch(
|
||||
f"/api/v1/tasks/{overdue['id']}",
|
||||
json={"completed": True, "version": overdue["version"]},
|
||||
)
|
||||
assert completed_overdue.status_code == 200
|
||||
assert datetime.fromisoformat(completed_overdue.json()["completed_at"]) == completed_at
|
||||
|
||||
completed_today = client.patch(
|
||||
f"/api/v1/tasks/{today_due['id']}",
|
||||
json={"completed": True, "version": today_due["version"]},
|
||||
)
|
||||
assert completed_today.status_code == 200
|
||||
assert datetime.fromisoformat(completed_today.json()["completed_at"]) == completed_at
|
||||
|
||||
today = client.get(
|
||||
"/api/v1/tasks",
|
||||
params={
|
||||
"due_from": "2026-09-15T00:00:00Z",
|
||||
"due_to": "2026-09-16T00:00:00Z",
|
||||
"completed_from": "2026-09-15T00:00:00Z",
|
||||
"completed_to": "2026-09-16T00:00:00Z",
|
||||
},
|
||||
)
|
||||
assert today.status_code == 200
|
||||
assert {item["title"] for item in today.json()["items"]} == {"昨天截止今天完成", "今天截止今天完成", "今天未完成"}
|
||||
|
||||
hidden_completed = client.get(
|
||||
"/api/v1/tasks",
|
||||
params={
|
||||
"due_from": "2026-09-15T00:00:00Z",
|
||||
"due_to": "2026-09-16T00:00:00Z",
|
||||
"completed": False,
|
||||
},
|
||||
)
|
||||
assert hidden_completed.status_code == 200
|
||||
assert [item["title"] for item in hidden_completed.json()["items"]] == ["今天未完成"]
|
||||
|
||||
shown_completed = client.get(
|
||||
"/api/v1/tasks",
|
||||
params={
|
||||
"due_from": "2026-09-15T00:00:00Z",
|
||||
"due_to": "2026-09-16T00:00:00Z",
|
||||
"completed": True,
|
||||
"completed_from": "2026-09-15T00:00:00Z",
|
||||
"completed_to": "2026-09-16T00:00:00Z",
|
||||
},
|
||||
)
|
||||
assert shown_completed.status_code == 200
|
||||
assert {item["title"] for item in shown_completed.json()["items"]} == {"昨天截止今天完成", "今天截止今天完成"}
|
||||
|
||||
|
||||
def test_batch_complete_records_completed_at(client, monkeypatch):
|
||||
client = initialized_client(client)
|
||||
inbox = client.get("/api/v1/lists").json()[0]
|
||||
first = client.post("/api/v1/tasks", json={"title": "批量1", "list_id": inbox["id"]}).json()
|
||||
second = client.post("/api/v1/tasks", json={"title": "批量2", "list_id": inbox["id"]}).json()
|
||||
completed_at = datetime(2026, 9, 15, 6, 0, tzinfo=UTC)
|
||||
monkeypatch.setattr("backend.recurrence_service.utcnow", lambda: completed_at)
|
||||
monkeypatch.setattr("backend.main.utcnow", lambda: completed_at)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/tasks/batch",
|
||||
json={
|
||||
"task_ids": [first["id"], second["id"]],
|
||||
"completed": True,
|
||||
"versions": {first["id"]: first["version"], second["id"]: second["version"]},
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
listed = client.get("/api/v1/tasks", params={"completed": True}).json()["items"]
|
||||
completed_map = {
|
||||
item["title"]: datetime.fromisoformat(item["completed_at"])
|
||||
for item in listed
|
||||
if item["title"] in {"批量1", "批量2"}
|
||||
}
|
||||
assert completed_map == {"批量1": completed_at, "批量2": completed_at}
|
||||
|
||||
|
||||
def test_reorder_tasks_rejects_mixed_parent_scopes_and_lists(client):
|
||||
client = initialized_client(client)
|
||||
inbox = client.get("/api/v1/lists").json()[0]
|
||||
|
||||
Reference in New Issue
Block a user