Some checks failed
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Failing after 1m57s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
parent_task_id mit Validierung und Roll-up; aufklappbarer Task-Baum unter Arbeitspaketen im Plan-Modus (max. 3 UI-Ebenen). Co-authored-by: Cursor <cursoragent@cursor.com>
109 lines
3.0 KiB
Python
109 lines
3.0 KiB
Python
"""Rekursive Tasks (AP1.5d)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from tests.factories import provision_user_in_tenant
|
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
|
|
|
|
|
def _create_action(client, token, initiative_id, title="AP Alpha"):
|
|
res = client.post(
|
|
f"/api/initiatives/{initiative_id}/actions",
|
|
json={"title": title},
|
|
headers=_auth(token),
|
|
)
|
|
assert res.status_code == 201
|
|
return res.json()
|
|
|
|
|
|
def _create_task(client, token, action_id, **payload):
|
|
return client.post(
|
|
f"/api/actions/{action_id}/tasks",
|
|
json=payload,
|
|
headers=_auth(token),
|
|
)
|
|
|
|
|
|
def test_nested_tasks_and_rollup(client):
|
|
user = provision_user_in_tenant(tenant_role="member")
|
|
token = _login(client, user)
|
|
initiative = _create_initiative(client, token, title="Task Tree").json()
|
|
action = _create_action(client, token, initiative["id"])
|
|
|
|
parent = _create_task(client, token, action["id"], title="Parent").json()
|
|
child = _create_task(
|
|
client,
|
|
token,
|
|
action["id"],
|
|
title="Child",
|
|
parent_task_id=parent["id"],
|
|
)
|
|
assert child.status_code == 201
|
|
child_id = child.json()["id"]
|
|
|
|
blocked = client.patch(
|
|
f"/api/tasks/{parent['id']}",
|
|
json={"status": "done"},
|
|
headers=_auth(token),
|
|
)
|
|
assert blocked.status_code == 400
|
|
|
|
done_child = client.patch(
|
|
f"/api/tasks/{child_id}",
|
|
json={"status": "done"},
|
|
headers=_auth(token),
|
|
)
|
|
assert done_child.status_code == 200
|
|
|
|
parent_after = client.get(
|
|
f"/api/actions/{action['id']}/tasks",
|
|
headers=_auth(token),
|
|
).json()
|
|
parent_row = next(item for item in parent_after if item["id"] == parent["id"])
|
|
assert parent_row["status"] == "done"
|
|
|
|
|
|
def test_task_cycle_rejected(client):
|
|
user = provision_user_in_tenant(tenant_role="member")
|
|
token = _login(client, user)
|
|
initiative = _create_initiative(client, token, title="Cycle").json()
|
|
action = _create_action(client, token, initiative["id"])
|
|
|
|
a = _create_task(client, token, action["id"], title="A").json()
|
|
b = _create_task(
|
|
client,
|
|
token,
|
|
action["id"],
|
|
title="B",
|
|
parent_task_id=a["id"],
|
|
).json()
|
|
|
|
res = client.patch(
|
|
f"/api/tasks/{a['id']}",
|
|
json={"parent_task_id": b["id"]},
|
|
headers=_auth(token),
|
|
)
|
|
assert res.status_code == 400
|
|
|
|
|
|
def test_delete_task_with_children_rejected(client):
|
|
user = provision_user_in_tenant(tenant_role="member")
|
|
token = _login(client, user)
|
|
initiative = _create_initiative(client, token, title="Delete Guard").json()
|
|
action = _create_action(client, token, initiative["id"])
|
|
|
|
parent = _create_task(client, token, action["id"], title="Parent").json()
|
|
_create_task(
|
|
client,
|
|
token,
|
|
action["id"],
|
|
title="Child",
|
|
parent_task_id=parent["id"],
|
|
)
|
|
|
|
res = client.delete(
|
|
f"/api/tasks/{parent['id']}",
|
|
headers=_auth(token),
|
|
)
|
|
assert res.status_code == 400
|