Files
HarborForge.Backend/tests/test_projects.py
zhi 403d66e1ba test(P14.1): add comprehensive backend API tests
Add test coverage for:
- test_auth.py: Login, JWT, protected endpoints (5 tests)
- test_users.py: User CRUD, permissions (8 tests)
- test_projects.py: Project CRUD, ownership (8 tests)
- test_milestones.py: Milestone CRUD, filtering (7 tests)
- test_tasks.py: Task CRUD, filtering by status/assignee (8 tests)
- test_comments.py: Comment CRUD, edit permissions (5 tests)
- test_roles.py: Role/permission management, assignments (9 tests)
- test_misc.py: Milestones global, notifications, activity log, API keys, dashboard, health (14 tests)

Total: 64 new tests covering all major API endpoints.
Uses existing pytest fixtures from conftest.py.
2026-03-19 12:38:14 +00:00

109 lines
4.1 KiB
Python

"""P14.1 — Projects API tests.
Covers:
- List projects
- Get project by ID
- Create project
- Update project
- Delete project
- Project ownership and permissions
"""
import pytest
class TestProjects:
"""Project management endpoints."""
def test_list_projects(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions):
"""User can list projects they have access to."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project1 = make_project(name="Project 1")
project2 = make_project(name="Project 2")
resp = client.get("/projects", headers=auth_header(user))
assert resp.status_code == 200
data = resp.json()
assert isinstance(data, list)
def test_get_project_by_id(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions):
"""Get specific project details."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project = make_project(name="Test Project", owner_id=user.id)
resp = client.get(f"/projects/{project.id}", headers=auth_header(user))
assert resp.status_code == 200
data = resp.json()
assert data["id"] == project.id
assert data["name"] == "Test Project"
def test_create_project(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""User can create project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
resp = client.post(
"/projects",
json={
"name": "New Project",
"description": "Test description",
"project_code": "TEST"
},
headers=auth_header(user)
)
assert resp.status_code == 201
data = resp.json()
assert data["name"] == "New Project"
assert data["project_code"] == "TEST"
assert "id" in data
def test_update_project(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions):
"""Project owner can update project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project = make_project(name="Old Name", owner_id=user.id)
resp = client.patch(
f"/projects/{project.id}",
json={"name": "Updated Name"},
headers=auth_header(user)
)
assert resp.status_code == 200
data = resp.json()
assert data["name"] == "Updated Name"
def test_delete_project(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions):
"""Project owner can delete project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project = make_project(owner_id=user.id)
resp = client.delete(f"/projects/{project.id}", headers=auth_header(user))
assert resp.status_code == 204
def test_non_owner_cannot_delete_project(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Non-owner cannot delete project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
owner = make_user(username="owner")
other = make_user(username="other")
project = make_project(owner_id=owner.id)
make_member(project.id, other.id, dev_role.id)
resp = client.delete(f"/projects/{project.id}", headers=auth_header(other))
assert resp.status_code == 403
def test_project_code_generation(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Project code is auto-generated if not provided."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
resp = client.post(
"/projects",
json={"name": "Auto Code Project"},
headers=auth_header(user)
)
assert resp.status_code == 201
data = resp.json()
assert data["project_code"].startswith("P")