test_recaptcha.py
1 from contextlib import asynccontextmanager 2 from typing import Any, AsyncIterator 3 from unittest.mock import AsyncMock, MagicMock 4 5 import pytest 6 from _pytest.monkeypatch import MonkeyPatch 7 from pytest_mock import MockerFixture 8 9 from .._utils import mock_asynccontextmanager 10 from api.settings import settings 11 from api.utils import recaptcha 12 13 14 @pytest.mark.parametrize( 15 "secret,sitekey,expected", 16 [("", "", False), (None, None, False), ("foo", "", False), ("", "bar", False), ("foo", "bar", True)], 17 ) 18 async def test__recaptcha_enabled( 19 secret: str | None, sitekey: str | None, expected: bool, monkeypatch: MonkeyPatch 20 ) -> None: 21 monkeypatch.setattr(settings, "recaptcha_sitekey", sitekey) 22 monkeypatch.setattr(settings, "recaptcha_secret", secret) 23 24 assert recaptcha.recaptcha_enabled() == expected 25 26 27 async def test__check_recaptcha(mocker: MockerFixture, monkeypatch: MonkeyPatch) -> None: 28 client_patch = mocker.patch("aiohttp.ClientSession") 29 30 secret = MagicMock() 31 token = MagicMock() 32 expected = MagicMock() 33 34 session = MagicMock() 35 response = AsyncMock() 36 37 client_patch.side_effect, func_callbacks, assert_calls = mock_asynccontextmanager(3, session) 38 39 @asynccontextmanager 40 async def session_context(url: str, data: dict[str, Any]) -> AsyncIterator[AsyncMock]: 41 assert url == "https://www.google.com/recaptcha/api/siteverify" 42 assert data == {"secret": secret, "response": token} 43 44 func_callbacks[0]() 45 yield response 46 func_callbacks[2]() 47 48 session.post.side_effect = session_context 49 response.json.side_effect = lambda: func_callbacks[1]() or {"success": expected} 50 51 monkeypatch.setattr(settings, "recaptcha_secret", secret) 52 assert await recaptcha.check_recaptcha(token) == expected 53 54 assert_calls() 55 client_patch.assert_called_once() 56 session.post.assert_called_once() 57 response.json.assert_called_once()