Coverage for test\test_exception_handlers.py: 99%
116 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
1import pytest
2from nexios import get_application, NexiosApp
3from nexios.exceptions import HTTPException, NotFoundException
4from nexios.http import Request, Response
5from nexios.testing import Client
6from typing import Tuple
9@pytest.fixture
10async def async_client():
11 app = get_application() # Fresh app instance for each test
12 async with Client(app, log_requests=True) as c:
13 yield c, app
16async def test_default_404_handler(async_client: Tuple[Client, NexiosApp]):
17 client, app = async_client
19 @app.get("/existing-route")
20 async def existing_route(req: Request, res: Response):
21 return res.text("OK")
23 # Test non-existent route
24 response = await client.get("/non-existent-route")
25 assert response.status_code == 404
26 assert "Not Found" in response.text
29async def test_custom_404_handler(async_client: Tuple[Client, NexiosApp]):
30 client, app = async_client
32 async def custom_404_handler(req: Request, res: Response, exc: NotFoundException):
33 return res.json({"error": "Custom not found"}, status_code=404)
35 app.add_exception_handler(NotFoundException, custom_404_handler)
37 response = await client.get("/non-existent-route")
38 assert response.status_code == 404
39 assert response.json() == {"error": "Custom not found"}
42async def test_http_exception_handling(async_client: Tuple[Client, NexiosApp]):
43 client, app = async_client
45 @app.get("/test-http-exception")
46 async def test_route(req: Request, res: Response):
47 raise HTTPException(status_code=403, detail="Access denied")
49 response = await client.get("/test-http-exception")
50 assert response.status_code == 403
51 assert response.json() == "Access denied"
54async def test_custom_exception_handler(async_client: Tuple[Client, NexiosApp]):
55 client, app = async_client
57 class CustomException(Exception):
58 pass
60 @app.get("/test-custom-exception")
61 async def test_route(req: Request, res: Response):
62 raise CustomException("Something went wrong")
64 async def handle_custom_exception(
65 req: Request, res: Response, exc: CustomException
66 ):
67 return res.json({"error": str(exc)}, status_code=400)
69 app.add_exception_handler(CustomException, handle_custom_exception)
71 response = await client.get("/test-custom-exception")
72 assert response.status_code == 400
73 assert response.json() == {"error": "Something went wrong"}
76async def test_status_code_exception_handler(async_client: Tuple[Client, NexiosApp]):
77 client, app = async_client
79 @app.get("/test-status-code")
80 async def test_route(req: Request, res: Response):
81 raise HTTPException(status_code=418, detail="I'm a teapot")
83 async def handle_teapot(req: Request, res: Response, exc: HTTPException):
84 return res.json({"message": "This is a teapot"}, status_code=418)
86 app.add_exception_handler(418, handle_teapot)
88 response = await client.get("/test-status-code")
89 assert response.status_code == 418
90 assert response.json() == {"message": "This is a teapot"}
93async def test_exception_handler_ordering(async_client: Tuple[Client, NexiosApp]):
94 client, app = async_client
96 class SpecificException(HTTPException):
97 pass
99 class GeneralException(HTTPException):
100 pass
102 @app.get("/test-specific")
103 async def test_specific(req: Request, res: Response):
104 raise SpecificException(status_code=400, detail="Specific error")
106 @app.get("/test-general")
107 async def test_general(req: Request, res: Response):
108 raise GeneralException(status_code=400, detail="General error")
110 # Register general handler first
111 async def general_handler(req: Request, res: Response, exc: HTTPException):
112 return res.text("General handler")
114 # Register specific handler second
115 async def specific_handler(req: Request, res: Response, exc: SpecificException):
116 return res.text("Specific handler")
118 app.add_exception_handler(HTTPException, general_handler)
119 app.add_exception_handler(SpecificException, specific_handler)
121 # Specific exception should use specific handler
122 response = await client.get("/test-specific")
123 assert response.text == "Specific handler"
125 # General exception should use general handler
126 response = await client.get("/test-general")
127 assert response.text == "General handler"
130async def test_exception_with_headers(async_client: Tuple[Client, NexiosApp]):
131 client, app = async_client
133 @app.get("/test-headers")
134 async def test_route(req: Request, res: Response):
135 raise HTTPException(
136 status_code=403, detail="Forbidden", headers={"X-Custom-Header": "value"}
137 )
139 response = await client.get("/test-headers")
140 assert response.status_code == 403
141 assert response.headers["x-custom-header"] == "value"
144async def test_middleware_exception_handling(async_client: Tuple[Client, NexiosApp]):
145 client, app = async_client
147 async def error_middleware(req: Request, res: Response, call_next):
148 try:
149 return await call_next()
150 except Exception as exc:
151 return res.json({"middleware_error": str(exc)}, status_code=500)
153 app.add_middleware(error_middleware)
155 @app.get("/test-middleware-error")
156 async def test_route(req: Request, res: Response):
157 raise ValueError("Error in route")
159 response = await client.get("/test-middleware-error")
160 assert response.status_code == 500
161 assert response.json() == {"middleware_error": "Error in route"}
164async def test_combined_exception_handling(async_client: Tuple[Client, NexiosApp]):
165 client, app = async_client
167 class CustomError(Exception):
168 pass
170 async def custom_handler(req: Request, res: Response, exc: CustomError):
171 return res.json({"custom": True}, status_code=400)
173 app.add_exception_handler(CustomError, custom_handler)
175 @app.get("/test-combined")
176 async def test_route(req: Request, res: Response):
177 raise CustomError("Combined test")
179 response = await client.get("/test-combined")
180 assert response.status_code == 400
181 assert response.json() == {"custom": True}