from __future__ import annotations from fastapi import HTTPException from fastapi.testclient import TestClient from app.main import app, create_app def assert_contract_error(payload: dict, code: str) -> None: assert payload["error"] == code assert isinstance(payload["message"], str) assert "details" in payload assert "request_id" in payload def test_app_error_uses_top_level_api_error_contract() -> None: client = TestClient(app) response = client.get("/api/v1/external/providers/unknown") assert response.status_code == 404 assert_contract_error(response.json(), "PROVIDER_NOT_FOUND") assert response.json()["message"] == "Provider not found" def test_http_exception_uses_top_level_api_error_contract() -> None: test_app = create_app() @test_app.get("/__test__/http-error") def raise_http_error() -> None: raise HTTPException(status_code=404, detail="Project not found") client = TestClient(test_app) response = client.get("/__test__/http-error") assert response.status_code == 404 assert_contract_error(response.json(), "HTTP_ERROR") assert response.json()["message"] == "Project not found" def test_validation_error_uses_top_level_api_error_contract() -> None: client = TestClient(app) response = client.get("/api/v1/projects/not-a-uuid") assert response.status_code == 422 assert_contract_error(response.json(), "VALIDATION_ERROR") assert response.json()["message"] == "Validation failed" assert isinstance(response.json()["details"], list)