test(P14.1): add comprehensive backend API test suite

Add 134 tests as independent test project:
- test_auth.py (5): Login, JWT, protected endpoints
- test_users.py (8): User CRUD, permissions
- test_projects.py (8): Project CRUD, ownership
- test_milestones.py (7): Milestone CRUD, filtering
- test_tasks.py (8): Task CRUD, filtering
- test_comments.py (5): Comment CRUD, permissions
- test_roles.py (9): Role/permission management
- test_milestone_actions.py (17): Milestone state machine
- test_task_transitions.py (34): Task state machine
- test_propose.py (19): Propose CRUD, lifecycle
- test_misc.py (14): Notifications, activity, API keys, dashboard

Setup:
- conftest.py: SQLite in-memory DB, fixtures
- requirements.txt: Dependencies
- pyproject.toml: Pytest config
- README.md: Documentation
This commit is contained in:
zhi
2026-03-19 12:43:44 +00:00
parent 477419cb57
commit 5f6a3dffe4
29 changed files with 3117 additions and 0 deletions

59
tests/test_auth.py Normal file
View File

@@ -0,0 +1,59 @@
"""P14.1 — Auth API tests.
Covers:
- Login with valid credentials
- Login with invalid credentials
- Token refresh
- Protected endpoint access with/without token
"""
import pytest
class TestAuth:
"""Authentication endpoints."""
def test_login_success(self, client, db, make_user):
"""Valid login returns JWT token."""
user = make_user(username="testuser", password="testpass123")
resp = client.post(
"/auth/token",
data={"username": "testuser", "password": "testpass123"}
)
assert resp.status_code == 200
data = resp.json()
assert "access_token" in data
assert data["token_type"] == "bearer"
def test_login_invalid_password(self, client, db, make_user):
"""Invalid password returns 401."""
make_user(username="testuser", password="testpass123")
resp = client.post(
"/auth/token",
data={"username": "testuser", "password": "wrongpass"}
)
assert resp.status_code == 401
def test_login_nonexistent_user(self, client, db):
"""Non-existent user returns 401."""
resp = client.post(
"/auth/token",
data={"username": "nosuchuser", "password": "anypass"}
)
assert resp.status_code == 401
def test_protected_endpoint_without_token(self, client):
"""Accessing protected endpoint without token returns 401."""
resp = client.get("/users/me")
assert resp.status_code == 401
def test_protected_endpoint_with_token(self, client, db, make_user, auth_header):
"""Accessing protected endpoint with valid token succeeds."""
user = make_user()
resp = client.get("/users/me", headers=auth_header(user))
assert resp.status_code == 200
data = resp.json()
assert data["id"] == user.id
assert data["username"] == user.username