import json import pytest from backend.app import create_app @pytest.fixture def client(): """ Creates a test client from your Flask app. """ app = create_app() app.config["TESTING"] = True with app.test_client() as client: yield client @pytest.fixture def auth_headers(client): """ Registers a test user and returns an authorization header. """ import uuid unique_suffix = str(uuid.uuid4())[:8] username = f"activityuser_{unique_suffix}" email = f"{username}@example.com" reg_payload = {"username": username, "email": email, "password": "TestPassword123"} reg_resp = client.post("/api/register", data=json.dumps(reg_payload), content_type="application/json") assert reg_resp.status_code == 201, f"Registration failed: {reg_resp.data.decode()}" data = json.loads(reg_resp.data) token = data["token"] return {"Authorization": f"Bearer {token}"} @pytest.fixture def project_id(client, auth_headers): """ Creates a project for the user so we can attach activity logs to it. Returns the project ID as a string. """ payload = { "name": "Activity Test Project", "topic": "Log Testing", "description": "Project used for testing activity logs." } resp = client.post("/api/projects", data=json.dumps(payload), content_type="application/json", headers=auth_headers) assert resp.status_code == 201, f"Project creation failed: {resp.data.decode()}" data = json.loads(resp.data) return data["project_id"] def test_list_activity_empty(client, auth_headers, project_id): """ No logs exist initially, so listing with ?projectId=xxx returns empty array. """ url = f"/api/project_activity?projectId={project_id}" resp = client.get(url, headers=auth_headers) assert resp.status_code == 200, f"List logs failed: {resp.data.decode()}" data = json.loads(resp.data) assert "activity_logs" in data assert len(data["activity_logs"]) == 0 def test_create_activity(client, auth_headers, project_id): """ Create an activity log for the project, then verify it appears in the listing. """ payload = { "projectId": project_id, "activityType": "URL added", "message": "Added a new URL to the project." } create_resp = client.post("/api/project_activity", data=json.dumps(payload), content_type="application/json", headers=auth_headers) assert create_resp.status_code == 201, f"Create activity failed: {create_resp.data.decode()}" create_data = json.loads(create_resp.data) assert "activity_id" in create_data # Now list logs list_resp = client.get(f"/api/project_activity?projectId={project_id}", headers=auth_headers) assert list_resp.status_code == 200 list_data = json.loads(list_resp.data) logs = list_data.get("activity_logs", []) assert len(logs) == 1 assert logs[0]["activityType"] == "URL added" assert logs[0]["message"] == "Added a new URL to the project." def test_create_activity_invalid_project(client, auth_headers): """ If projectId is invalid or not found, we expect 400 or 404. """ # Invalid format payload1 = { "projectId": "not_a_valid_objectid", "activityType": "Test", "message": "" } resp1 = client.post("/api/project_activity", data=json.dumps(payload1), content_type="application/json", headers=auth_headers) assert resp1.status_code == 400, f"Expected 400 for invalid projectId format, got {resp1.status_code}" # 404 if project doesn't exist payload2 = { "projectId": "64f3f000000000000000abcd", # random objectId "activityType": "Test", "message": "" } resp2 = client.post("/api/project_activity", data=json.dumps(payload2), content_type="application/json", headers=auth_headers) assert resp2.status_code == 404, f"Expected 404 for non-existent project, got {resp2.status_code}" def test_list_activity_pagination(client, auth_headers, project_id): """ Create multiple logs, then retrieve them with offset/limit. """ # Create 5 logs for i in range(5): pay = { "projectId": project_id, "activityType": f"LogType{i}", "message": f"Message {i}" } resp = client.post("/api/project_activity", data=json.dumps(pay), content_type="application/json", headers=auth_headers) assert resp.status_code == 201 # List with limit=2, offset=0 resp_list1 = client.get(f"/api/project_activity?projectId={project_id}&limit=2&offset=0", headers=auth_headers) assert resp_list1.status_code == 200 data1 = json.loads(resp_list1.data) logs1 = data1["activity_logs"] assert len(logs1) == 2 # List with limit=2, offset=2 resp_list2 = client.get(f"/api/project_activity?projectId={project_id}&limit=2&offset=2", headers=auth_headers) data2 = json.loads(resp_list2.data) logs2 = data2["activity_logs"] assert len(logs2) == 2 def test_delete_activity(client, auth_headers, project_id): """ By default, only the project owner can delete logs. We'll test that scenario. """ # Create a log payload = { "projectId": project_id, "activityType": "DeleteCheck", "message": "Testing delete." } create_resp = client.post("/api/project_activity", data=json.dumps(payload), content_type="application/json", headers=auth_headers) assert create_resp.status_code == 201 activity_id = json.loads(create_resp.data)["activity_id"] # Delete it del_resp = client.delete(f"/api/project_activity/{activity_id}", headers=auth_headers) assert del_resp.status_code == 200, f"Delete log failed: {del_resp.data.decode()}" # Confirm it's gone list_resp = client.get(f"/api/project_activity?projectId={project_id}", headers=auth_headers) data = json.loads(list_resp.data) logs_left = [a for a in data["activity_logs"] if a["_id"] == activity_id] assert len(logs_left) == 0, "Activity log was not deleted properly."