"""Tests for the jobs page route.""" import asyncio from uuid import uuid4 import pytest from transcription.db import session_scope from transcription.db.models import Document from transcription.db.models import JobStatus @pytest.mark.integration class TestPageRendering: """Verify jobs routes render correctly with real app wiring.""" def test_jobs_page_renders_empty_state(self, app_client): """GET /ui/jobs renders the page and empty-state text when no jobs exist.""" _, client = app_client response = client.get("/ui/jobs") assert response.status_code == 200 assert "Create job" in response.text assert "No active or historical processing jobs found." in response.text def test_job_create_page_requires_existing_documents(self, app_client): """GET /ui/jobs/new shows guidance when no Documents exist.""" _, 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 assert "Create document" in response.text def test_job_create_page_lists_available_documents(self, app_client): """GET /ui/jobs/new renders document choices when Documents exist.""" _, client = app_client async def _seed_document() -> None: async with session_scope() as session: session.add(Document(name="Seeded Document")) await session.commit() asyncio.run(_seed_document()) response = client.get("/ui/jobs/new") assert response.status_code == 200 assert "Create Processing Job" in response.text assert "Seeded Document" in response.text assert "Files are processed alphabetically by original filename." in response.text assert "No files uploaded yet." in response.text assert "Select source files or a folder" in response.text def test_jobs_page_lists_seeded_jobs(self, app_client, seed_job): """GET /ui/jobs lists seeded jobs from the in-memory database.""" _, client = app_client seed_job(filename="sample.pdf", status=JobStatus.TRANSCRIBED, transcription_text="done") response = client.get("/ui/jobs") assert response.status_code == 200 assert "sample.pdf" in response.text assert "transcribed" in response.text def test_job_detail_page_renders_document_links(self, app_client, seed_job): """GET /ui/jobs/{job_id} renders document-scoped navigation links.""" _, client = app_client job_id = seed_job( filename="detail.pdf", status=JobStatus.TRANSCRIBED, transcription_text="original text", ) response = client.get(f"/ui/jobs/{job_id}") assert response.status_code == 200 assert "Job" in response.text assert "Provider:" in response.text assert "Model:" in response.text assert "Prompt:" in response.text assert "Retry Count:" in response.text assert "Last Updated:" in response.text assert "document links" in response.text.lower() assert "Sources" in response.text assert "Jobs" in response.text assert "Delete Job" in response.text def test_job_detail_page_rejects_invalid_id(self, app_client): """GET /ui/jobs/{job_id} shows validation feedback for malformed IDs.""" _, client = app_client response = client.get("/ui/jobs/not-a-uuid") assert response.status_code == 200 assert "Invalid job id" in response.text def test_job_detail_page_handles_missing_job(self, app_client): """GET /ui/jobs/{job_id} shows not-found state for unknown IDs.""" _, client = app_client missing_id = uuid4() response = client.get(f"/ui/jobs/{missing_id}") assert response.status_code == 200 assert "Job not found" in response.text def test_job_detail_page_shows_cancel_and_resubmit_when_queued(self, app_client, seed_job): """GET /ui/jobs/{job_id} exposes cancel/resubmit controls for queued jobs.""" _, client = app_client job_id = seed_job( filename="no-revision.pdf", status=JobStatus.QUEUED, transcription_text=None, ) response = client.get(f"/ui/jobs/{job_id}") assert response.status_code == 200 assert "Cancel" in response.text assert "Resubmit" in response.text assert "Delete Job" in response.text def test_job_cancel_page_renders_confirmation(self, app_client, seed_job): _, client = app_client job_id = seed_job(filename="cancel-ready.pdf", status=JobStatus.PROCESSING) response = client.get(f"/ui/jobs/{job_id}/cancel") assert response.status_code == 200 assert "Cancel Processing Job" in response.text assert "Cancel job" in response.text def test_job_resubmit_page_renders_confirmation(self, app_client, seed_job): _, client = app_client job_id = seed_job(filename="resubmit-ready.pdf", status=JobStatus.FAILED, transcription_text=None) response = client.get(f"/ui/jobs/{job_id}/resubmit") assert response.status_code == 200 assert "Resubmit Job" in response.text assert "Resubmit now" in response.text def test_job_delete_page_shows_confirmation_when_not_processing(self, app_client, seed_job): _, client = app_client job_id = seed_job(filename="delete-ready.pdf", status=JobStatus.TRANSCRIBED) response = client.get(f"/ui/jobs/{job_id}/delete") assert response.status_code == 200 assert "Delete job" in response.text assert "This action permanently deletes the job." in response.text assert "Delete job permanently" in response.text def test_job_delete_page_shows_blocked_state_when_processing(self, app_client, seed_job): _, client = app_client job_id = seed_job(filename="delete-blocked.pdf", status=JobStatus.PROCESSING) response = client.get(f"/ui/jobs/{job_id}/delete") assert response.status_code == 200 assert "Delete is blocked while the job is processing." in response.text assert "Wait for processing to complete, then retry delete." in response.text