"""Tests for API error response envelope handlers.""" import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from transcription.api.errors import register_error_handlers from transcription.errors import AppError from transcription.errors import ErrorCategory @pytest.mark.integration class TestApiErrorResponses: """Verify API-level error serialization and status mapping.""" def test_app_error_returns_structured_envelope(self): """AppError maps to policy envelope fields and status code.""" app = FastAPI() register_error_handlers(app) @app.get("/boom") def boom() -> dict[str, str]: raise AppError( "Bad upload payload", category=ErrorCategory.VALIDATION, suggestion="Upload a non-empty file", error_id="abc12345", ) client = TestClient(app) response = client.get("/boom") assert response.status_code == 400 payload = response.json() assert payload["error_id"] == "abc12345" assert payload["category"] == "validation" assert payload["message"] == "Bad upload payload" assert payload["suggestion"] == "Upload a non-empty file" assert "timestamp" in payload def test_unexpected_error_returns_internal_envelope(self): """Unexpected exceptions map to canonical internal category with 500.""" app = FastAPI() register_error_handlers(app) @app.get("/explode") def explode() -> dict[str, str]: raise RuntimeError("unexpected failure") client = TestClient(app, raise_server_exceptions=False) response = client.get("/explode") assert response.status_code == 500 payload = response.json() assert payload["category"] == "internal" assert "error_id" in payload assert payload["suggestion"] @pytest.mark.parametrize( ("category", "expected_status", "expected_envelope_category"), [ (ErrorCategory.USER_INPUT, 400, "validation"), (ErrorCategory.NOT_FOUND, 404, "not_found"), (ErrorCategory.CONFLICT, 409, "conflict"), (ErrorCategory.EXTERNAL_PROVIDER, 503, "external"), (ErrorCategory.EXTERNAL_TIMEOUT, 503, "timeout"), (ErrorCategory.INFRA_TRANSIENT, 503, "timeout"), (ErrorCategory.PROCESSING, 500, "internal"), (ErrorCategory.INFRA_PERSISTENT, 500, "internal"), (ErrorCategory.INTERNAL_UNEXPECTED, 500, "internal"), ], ) def test_app_error_category_mapping_uses_canonical_envelope_taxonomy( self, category: ErrorCategory, expected_status: int, expected_envelope_category: str, ): app = FastAPI() register_error_handlers(app) @app.get("/category") def category_route() -> dict[str, str]: raise AppError( "Category test", category=category, suggestion="retry", error_id="cat12345", ) client = TestClient(app) response = client.get("/category") assert response.status_code == expected_status assert response.json()["category"] == expected_envelope_category