|
1 | 1 | import re
|
2 | 2 | import string
|
3 | 3 | import random
|
4 |
| -from datetime import timedelta |
| 4 | +from datetime import timedelta, UTC, datetime |
5 | 5 | from urllib.parse import urlparse, parse_qs
|
6 | 6 | from starlette.datastructures import URLPath
|
7 | 7 | from main import app
|
|
13 | 13 | validate_token,
|
14 | 14 | generate_password_reset_url,
|
15 | 15 | COMPILED_PASSWORD_PATTERN,
|
16 |
| - convert_python_regex_to_html |
| 16 | + convert_python_regex_to_html, |
| 17 | + generate_email_update_url, |
| 18 | + send_email_update_confirmation, |
| 19 | + get_user_from_email_update_token |
17 | 20 | )
|
| 21 | +from unittest.mock import patch, MagicMock |
| 22 | +from utils.models import User, EmailUpdateToken |
18 | 23 |
|
19 | 24 |
|
20 | 25 | def test_convert_python_regex_to_html() -> None:
|
@@ -146,3 +151,100 @@ def test_password_pattern() -> None:
|
146 | 151 | # No special character
|
147 | 152 | password = "aA1" * 3
|
148 | 153 | assert re.match(COMPILED_PASSWORD_PATTERN, password) is None
|
| 154 | + |
| 155 | +def test_email_update_url_generation() -> None: |
| 156 | + """ |
| 157 | + Tests that the email update confirmation URL is correctly formatted and contains |
| 158 | + the required query parameters. |
| 159 | + """ |
| 160 | + test_user_id = 123 |
| 161 | + test_token = "abc123" |
| 162 | + test_new_email = "[email protected]" |
| 163 | + |
| 164 | + url = generate_email_update_url(test_user_id, test_token, test_new_email) |
| 165 | + |
| 166 | + # Parse the URL |
| 167 | + parsed = urlparse(url) |
| 168 | + query_params = parse_qs(parsed.query) |
| 169 | + |
| 170 | + # Get the actual path from the FastAPI app |
| 171 | + confirm_email_path: URLPath = app.url_path_for("confirm_email_update") |
| 172 | + |
| 173 | + # Verify URL path |
| 174 | + assert parsed.path == str(confirm_email_path) |
| 175 | + |
| 176 | + # Verify query parameters |
| 177 | + assert "user_id" in query_params |
| 178 | + assert "token" in query_params |
| 179 | + assert "new_email" in query_params |
| 180 | + assert query_params["user_id"][0] == str(test_user_id) |
| 181 | + assert query_params["token"][0] == test_token |
| 182 | + assert query_params["new_email"][0] == test_new_email |
| 183 | + |
| 184 | +@patch('resend.Emails.send') |
| 185 | +def test_send_email_update_confirmation(mock_send: MagicMock) -> None: |
| 186 | + """ |
| 187 | + Tests the email update confirmation sending functionality. |
| 188 | + """ |
| 189 | + # Mock session and dependencies |
| 190 | + session = MagicMock() |
| 191 | + session.exec.return_value.first.return_value = None # No existing token |
| 192 | + |
| 193 | + current_email = "[email protected]" |
| 194 | + |
| 195 | + user_id = 123 |
| 196 | + |
| 197 | + # Mock successful email send |
| 198 | + mock_send.return_value = {"id": "test_email_id"} |
| 199 | + |
| 200 | + # Test successful email sending |
| 201 | + send_email_update_confirmation(current_email, new_email, user_id, session) |
| 202 | + |
| 203 | + # Verify session interactions |
| 204 | + assert session.add.called |
| 205 | + assert session.commit.called |
| 206 | + |
| 207 | + # Verify email was sent with correct parameters |
| 208 | + mock_send.assert_called_once() |
| 209 | + call_args = mock_send.call_args[0][0] |
| 210 | + assert call_args["to"] == [current_email] |
| 211 | + assert call_args["subject"] == "Confirm Email Update" |
| 212 | + assert "from" in call_args |
| 213 | + assert "html" in call_args |
| 214 | + |
| 215 | + # Test existing token case |
| 216 | + session.reset_mock() |
| 217 | + session.exec.return_value.first.return_value = EmailUpdateToken() # Existing token |
| 218 | + |
| 219 | + send_email_update_confirmation(current_email, new_email, user_id, session) |
| 220 | + |
| 221 | + # Verify no new token was created or email sent |
| 222 | + assert not session.add.called |
| 223 | + assert not session.commit.called |
| 224 | + assert mock_send.call_count == 1 # Still just one call from before |
| 225 | + |
| 226 | +def test_get_user_from_email_update_token() -> None: |
| 227 | + """ |
| 228 | + Tests retrieving a user using an email update token. |
| 229 | + """ |
| 230 | + session = MagicMock() |
| 231 | + |
| 232 | + # Test valid token |
| 233 | + mock_user = User( id=1, email="[email protected]") |
| 234 | + mock_token = EmailUpdateToken( |
| 235 | + user_id=1, |
| 236 | + token="valid_token", |
| 237 | + expires_at=datetime.now(UTC) + timedelta(hours=1), |
| 238 | + used=False |
| 239 | + ) |
| 240 | + session.exec.return_value.first.return_value = (mock_user, mock_token) |
| 241 | + |
| 242 | + user, token = get_user_from_email_update_token(1, "valid_token", session) |
| 243 | + assert user == mock_user |
| 244 | + assert token == mock_token |
| 245 | + |
| 246 | + # Test invalid token |
| 247 | + session.exec.return_value.first.return_value = None |
| 248 | + user, token = get_user_from_email_update_token(1, "invalid_token", session) |
| 249 | + assert user is None |
| 250 | + assert token is None |
0 commit comments