"""Tests for the jobs page routes and action handlers.""" import pytest from sqlmodel import select from transcription.db import session_scope from transcription.db.models import Document, Job, JobSourceStatus, JobStatus # --- Helper Fixtures --- @pytest.fixture async def seed_document_with_unlinked_job(): """Seed a document and a queued job for testing route actions.""" async with session_scope() as session: document = Document(name="Test Archival Letter", document_type="letter") session.add(document) await session.flush() job = Job( document_id=document.id, status=JobStatus.QUEUED, provider="openai", model="gpt-4o", ) session.add(job) await session.commit() return str(document.id), str(job.id) # --- Integration Tests for Jobs Route Handlers --- @pytest.mark.integration class TestJobsPageRendering: """Verify jobs list, creation, detail, and lifecycle action routes.""" def test_jobs_page_renders_empty_state(self, app_client): _, client = app_client response = client.get("/ui/jobs") assert response.status_code == 200 assert "Transcription Pipeline Jobs" in response.text assert "No active or historical processing jobs found." in response.text def test_jobs_page_lists_seeded_jobs(self, app_client, seed_job): _, client = app_client job_id = seed_job(filename="seeded-document-page.png") response = client.get("/ui/jobs") assert response.status_code == 200 assert str(job_id) in response.text assert "seeded-document-page.png" in response.text @pytest.mark.asyncio async def test_job_create_page_shows_empty_document_warning_when_no_docs(self, app_client): _, client = app_client response = client.get("/ui/jobs/new") assert response.status_code == 200 assert "Create Processing Job" in response.text assert "No documents available. Create a Document before creating a Job." in response.text @pytest.mark.asyncio async def test_job_create_page_preselects_document_from_query_param(self, app_client): _, client = app_client async with session_scope() as session: doc = Document(name="Preselected Journal Entry", document_type="journal") session.add(doc) await session.commit() doc_id = str(doc.id) response = client.get(f"/ui/jobs/new?document_id={doc_id}") assert response.status_code == 200 assert "Create Processing Job" in response.text assert "Preselected Journal Entry" in response.text @pytest.mark.asyncio async def test_job_detail_page_renders_logistics_and_links( self, app_client, seed_document_with_unlinked_job ): _, client = app_client _, job_id = seed_document_with_unlinked_job response = client.get(f"/ui/jobs/{job_id}") assert response.status_code == 200 assert f"Job Record: {job_id}" in response.text assert "Execution Logistics" in response.text assert "openai" in response.text assert "gpt-4o" in response.text assert "View Linked Document" in response.text assert "View Linked Sources" in response.text @pytest.mark.asyncio async def test_job_cancel_page_renders_confirmation( self, app_client, seed_document_with_unlinked_job ): _, client = app_client _, job_id = seed_document_with_unlinked_job response = client.get(f"/ui/jobs/{job_id}/cancel") assert response.status_code == 200 assert "Cancel Processing Job" in response.text assert "Cancel stops processing" in response.text assert "Cancel job" in response.text @pytest.mark.asyncio async def test_job_resubmit_page_renders_counts( self, app_client, seed_job ): _, client = app_client job_id = seed_job( filename="failed-resubmit.png", status=JobStatus.FAILED, transcription_text=None, error_detail="Timeout", ) response = client.get(f"/ui/jobs/{job_id}/resubmit") assert response.status_code == 200 assert "Resubmit Job" in response.text assert "Non-Transcribed Sources:" in response.text assert "Resubmit now" in response.text @pytest.mark.asyncio async def test_job_delete_page_blocks_deletion_when_processing(self, app_client): _, client = app_client async with session_scope() as session: doc = Document(name="Processing Doc", document_type="letter") session.add(doc) await session.flush() job = Job(document_id=doc.id, status=JobStatus.PROCESSING) session.add(job) await session.commit() job_id = str(job.id) response = client.get(f"/ui/jobs/{job_id}/delete") assert response.status_code == 200 assert "Delete Processing Job" in response.text assert "Delete is blocked while the job is processing." in response.text @pytest.mark.asyncio async def test_job_delete_page_allows_deletion_for_queued_or_completed_job( self, app_client, seed_document_with_unlinked_job ): _, client = app_client _, job_id = seed_document_with_unlinked_job response = client.get(f"/ui/jobs/{job_id}/delete") assert response.status_code == 200 assert "Delete Processing Job" in response.text assert "Delete job permanently" in response.text assert "Delete is blocked" not in response.text