import pytest from datetime import datetime, timedelta from app import db from app.models import Project, Task, TimeEntry from factories import TimeEntryFactory @pytest.mark.smoke @pytest.mark.routes def test_edit_task_changes_project_and_updates_time_entries(authenticated_client, app, user, test_client): with app.app_context(): # Create two active projects under the same client project1 = Project(name="Project One", client_id=test_client.id, description="P1") project1.status = "active" project2 = Project(name="Project Two", client_id=test_client.id, description="P2") project2.status = "active" db.session.add_all([project1, project2]) db.session.commit() # Create a task on project1 task = Task(project_id=project1.id, name="Move Me", created_by=user.id) db.session.add(task) db.session.commit() # Create a time entry associated with this task and project1 start_time = datetime.utcnow() - timedelta(hours=2) end_time = datetime.utcnow() - timedelta(hours=1) entry = TimeEntryFactory( user_id=user.id, project_id=project1.id, task_id=task.id, start_time=start_time, end_time=end_time, notes="Work on task before moving", ) db.session.commit() # Store IDs before POST request task_id = task.id entry_id = entry.id project2_id = project2.id # Store project2 ID before leaving app context # Submit edit form to change the project to project2 (POST happens outside app context) resp = authenticated_client.post( f"/tasks/{task_id}/edit", data={ "project_id": str(project2_id), # Use stored ID "name": "Move Me", # Use explicit name "description": "", "priority": "medium", "status": "todo", # Include status to match current task status "estimated_hours": "", "due_date": "", "assigned_to": "", }, follow_redirects=True, # Follow redirects to see final response ) # Expect success (200 after redirect or 302 redirect) assert resp.status_code in ( 200, 302, 303, ), f"Expected 200/302/303, got {resp.status_code}. Response: {resp.get_data(as_text=True)[:500]}" # Re-query objects to verify project change persisted (within app context) with app.app_context(): task = Task.query.get(task_id) entry = TimeEntry.query.get(entry_id) assert task is not None, "Task should still exist" assert entry is not None, "Entry should still exist" assert task.project_id == project2_id, f"Task project_id is {task.project_id}, expected {project2_id}" assert entry.project_id == project2_id, f"Entry project_id is {entry.project_id}, expected {project2_id}"