personal-lifecycle-tracker / backend / tests / test_items.py
test_items.py
Raw
from __future__ import annotations

from fastapi.testclient import TestClient


def test_items_crud_and_completion(test_client: TestClient):
    # 1. List existing seed items
    list_res = test_client.get("/api/v1/items")
    assert list_res.status_code == 200
    items = list_res.json()
    assert len(items) > 0

    # 2. Create item
    res = test_client.post(
        "/api/v1/items",
        json={
            "name": "Passport Renewal",
            "lifecycleType": "renewal",
            "dueDate": "2026-11-20",
        },
    )
    assert res.status_code == 201
    item = res.json()
    item_id = item["id"]
    assert item["name"] == "Passport Renewal"
    assert item["lifecycleType"] == "renewal"
    assert item["status"] == "active"
    assert item["ownerEmail"] == "alex@example.com"

    # 3. Get item by ID
    get_res = test_client.get(f"/api/v1/items/{item_id}")
    assert get_res.status_code == 200
    assert get_res.json()["id"] == item_id

    # 4. Update item
    patch_res = test_client.patch(
        f"/api/v1/items/{item_id}",
        json={"name": "Updated Passport Renewal", "dueDate": "2026-12-01"},
    )
    assert patch_res.status_code == 200
    assert patch_res.json()["name"] == "Updated Passport Renewal"
    assert patch_res.json()["dueDate"] == "2026-12-01"

    # 5. Toggle complete
    complete_res = test_client.post(f"/api/v1/items/{item_id}/complete")
    assert complete_res.status_code == 200
    assert complete_res.json()["status"] == "completed"

    # Toggle back to active
    active_res = test_client.post(f"/api/v1/items/{item_id}/complete")
    assert active_res.status_code == 200
    assert active_res.json()["status"] == "active"

    # 6. Delete item
    del_res = test_client.delete(f"/api/v1/items/{item_id}")
    assert del_res.status_code == 204

    # 7. Verify deletion
    not_found_res = test_client.get(f"/api/v1/items/{item_id}")
    assert not_found_res.status_code == 404


def test_items_filtering(test_client: TestClient):
    # Filter by type
    renewals_res = test_client.get("/api/v1/items?type=renewal")
    assert renewals_res.status_code == 200
    for itm in renewals_res.json():
        assert itm["lifecycleType"] == "renewal"

    # Filter personal only (groupId=null)
    personal_res = test_client.get("/api/v1/items?groupId=null")
    assert personal_res.status_code == 200
    for itm in personal_res.json():
        assert itm["groupId"] is None

    # Filter specific group
    group_res = test_client.get("/api/v1/items?groupId=group_home")
    assert group_res.status_code == 200
    for itm in group_res.json():
        assert itm["groupId"] == "group_home"

    # Search query
    search_res = test_client.get("/api/v1/items?searchQuery=Auto")
    assert search_res.status_code == 200
    assert any("Auto" in itm["name"] for itm in search_res.json())


def test_create_item_with_auth_bearer(test_client: TestClient):
    # Signup a distinct user
    signup_res = test_client.post(
        "/api/v1/auth/signup",
        json={"email": "beareruser@example.com", "name": "Bearer User", "password": "password123"},
    )
    token = signup_res.json()["token"]
    headers = {"Authorization": f"Bearer {token}"}

    # Create item with Bearer header
    res = test_client.post(
        "/api/v1/items",
        json={"name": "Bicycle Service", "lifecycleType": "maintenance"},
        headers=headers,
    )
    assert res.status_code == 201
    item = res.json()
    assert item["ownerEmail"] == "beareruser@example.com"
    assert item["name"] == "Bicycle Service"


def test_items_not_found_errors(test_client: TestClient):
    assert test_client.get("/api/v1/items/non-existent-id").status_code == 404
    assert test_client.patch("/api/v1/items/non-existent-id", json={"name": "X"}).status_code == 404
    assert test_client.delete("/api/v1/items/non-existent-id").status_code == 404
    assert test_client.post("/api/v1/items/non-existent-id/complete").status_code == 404