72 lines
3 KiB
Python
72 lines
3 KiB
Python
|
|
"""Unit tests for passkey route error handling."""
|
||
|
|
from unittest.mock import patch, MagicMock
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from starlette.testclient import TestClient
|
||
|
|
|
||
|
|
# We need to test through the FastAPI app or build a minimal test client
|
||
|
|
from api.passkey_routes import passkey_router
|
||
|
|
from fastapi import FastAPI
|
||
|
|
|
||
|
|
|
||
|
|
def _build_app() -> FastAPI:
|
||
|
|
app = FastAPI()
|
||
|
|
app.include_router(passkey_router)
|
||
|
|
return app
|
||
|
|
|
||
|
|
|
||
|
|
class TestPasskeyErrorHandling:
|
||
|
|
"""Tests that passkey routes return generic error messages for internal exceptions."""
|
||
|
|
|
||
|
|
@patch("api.passkey_routes.passkey_service")
|
||
|
|
@patch("api.passkey_routes.UserRepository")
|
||
|
|
def test_register_begin_internal_error_returns_generic_message(
|
||
|
|
self, mock_user_repo: MagicMock, mock_service: MagicMock
|
||
|
|
) -> None:
|
||
|
|
mock_service.begin_registration.side_effect = RuntimeError("DB connection lost")
|
||
|
|
client = TestClient(_build_app())
|
||
|
|
resp = client.post("/api/passkey/register/begin", json={"email": "test@example.com"})
|
||
|
|
assert resp.status_code == 400
|
||
|
|
assert resp.json()["detail"] == "Registration failed. Please try again."
|
||
|
|
assert "DB connection lost" not in resp.json()["detail"]
|
||
|
|
|
||
|
|
@patch("api.passkey_routes.passkey_service")
|
||
|
|
@patch("api.passkey_routes.UserRepository")
|
||
|
|
def test_register_begin_value_error_returns_user_message(
|
||
|
|
self, mock_user_repo: MagicMock, mock_service: MagicMock
|
||
|
|
) -> None:
|
||
|
|
mock_service.begin_registration.side_effect = ValueError("Email already registered")
|
||
|
|
client = TestClient(_build_app())
|
||
|
|
resp = client.post("/api/passkey/register/begin", json={"email": "test@example.com"})
|
||
|
|
assert resp.status_code == 400
|
||
|
|
assert resp.json()["detail"] == "Email already registered"
|
||
|
|
|
||
|
|
@patch("api.passkey_routes.passkey_service")
|
||
|
|
@patch("api.passkey_routes.UserRepository")
|
||
|
|
def test_login_complete_internal_error_returns_generic_message(
|
||
|
|
self, mock_user_repo: MagicMock, mock_service: MagicMock
|
||
|
|
) -> None:
|
||
|
|
mock_service.complete_authentication.side_effect = RuntimeError("Crypto failure")
|
||
|
|
client = TestClient(_build_app())
|
||
|
|
resp = client.post(
|
||
|
|
"/api/passkey/login/complete",
|
||
|
|
json={"session_id": "abc", "credential": {"id": "x"}},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 400
|
||
|
|
assert resp.json()["detail"] == "Login could not be completed."
|
||
|
|
assert "Crypto failure" not in resp.json()["detail"]
|
||
|
|
|
||
|
|
@patch("api.passkey_routes.passkey_service")
|
||
|
|
@patch("api.passkey_routes.UserRepository")
|
||
|
|
def test_login_complete_value_error_returns_user_message(
|
||
|
|
self, mock_user_repo: MagicMock, mock_service: MagicMock
|
||
|
|
) -> None:
|
||
|
|
mock_service.complete_authentication.side_effect = ValueError("Invalid credential")
|
||
|
|
client = TestClient(_build_app())
|
||
|
|
resp = client.post(
|
||
|
|
"/api/passkey/login/complete",
|
||
|
|
json={"session_id": "abc", "credential": {"id": "x"}},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 400
|
||
|
|
assert resp.json()["detail"] == "Invalid credential"
|