9
9
from html import unescape
10
10
11
11
from main import app
12
- from utils .models import User , PasswordResetToken
12
+ from utils .models import User , PasswordResetToken , UserPassword , EmailUpdateToken
13
13
from utils .auth import (
14
14
create_access_token ,
15
15
verify_password ,
16
16
validate_token ,
17
+ get_password_hash
17
18
)
18
19
from .conftest import SetupError
19
20
@@ -199,7 +200,7 @@ def test_register_with_existing_email(unauth_client: TestClient, test_user: User
199
200
"confirm_password" : "Test123!@#"
200
201
}
201
202
)
202
- assert response .status_code == 400
203
+ assert response .status_code == 409
203
204
204
205
205
206
def test_login_with_invalid_credentials (unauth_client : TestClient , test_user : User ):
@@ -210,7 +211,7 @@ def test_login_with_invalid_credentials(unauth_client: TestClient, test_user: Us
210
211
"password" : "WrongPass123!@#"
211
212
}
212
213
)
213
- assert response .status_code == 400
214
+ assert response .status_code == 401
214
215
215
216
216
217
def test_password_reset_with_invalid_token (unauth_client : TestClient , test_user : User ):
@@ -223,7 +224,7 @@ def test_password_reset_with_invalid_token(unauth_client: TestClient, test_user:
223
224
"confirm_new_password" : "NewPass123!@#"
224
225
}
225
226
)
226
- assert response .status_code == 400
227
+ assert response .status_code == 401
227
228
228
229
229
230
def test_password_reset_email_url (unauth_client : TestClient , session : Session , test_user : User , mock_resend_send ):
@@ -264,3 +265,144 @@ def test_password_reset_email_url(unauth_client: TestClient, session: Session, t
264
265
assert parsed .path == str (reset_password_path )
265
266
assert query_params ["email" ][0 ] == test_user .email
266
267
assert query_params ["token" ][0 ] == reset_token .token
268
+
269
+
270
+ def test_request_email_update_success (auth_client : TestClient , test_user : User , mock_resend_send ):
271
+ """Test successful email update request"""
272
+
273
+
274
+ response = auth_client .post (
275
+ app .url_path_for ("request_email_update" ),
276
+ data = {"new_email" : new_email },
277
+ follow_redirects = False
278
+ )
279
+
280
+ assert response .status_code == 303
281
+ assert "profile?email_update_requested=true" in response .headers ["location" ]
282
+
283
+ # Verify email was "sent"
284
+ mock_resend_send .assert_called_once ()
285
+ call_args = mock_resend_send .call_args [0 ][0 ]
286
+
287
+ # Verify email content
288
+ assert call_args ["to" ] == [test_user .email ]
289
+ assert call_args [
"from" ]
== "[email protected] "
290
+ assert "Confirm Email Update" in call_args ["subject" ]
291
+ assert "confirm_email_update" in call_args ["html" ]
292
+ assert new_email in call_args ["html" ]
293
+
294
+
295
+ def test_request_email_update_already_registered (auth_client : TestClient , session : Session , test_user : User ):
296
+ """Test email update request with already registered email"""
297
+ # Create another user with the target email
298
+ existing_email = "[email protected] "
299
+ existing_user = User (
300
+ name = "Existing User" ,
301
+ email = existing_email ,
302
+ password = UserPassword (hashed_password = get_password_hash ("Test123!@#" ))
303
+ )
304
+ session .add (existing_user )
305
+ session .commit ()
306
+
307
+ response = auth_client .post (
308
+ app .url_path_for ("request_email_update" ),
309
+ data = {"new_email" : existing_email }
310
+ )
311
+
312
+ assert response .status_code == 409
313
+ assert "already registered" in response .text
314
+
315
+
316
+ def test_request_email_update_unauthenticated (unauth_client : TestClient ):
317
+ """Test email update request without authentication"""
318
+ response = unauth_client .post (
319
+ app .url_path_for ("request_email_update" ),
320
+ data = {
"new_email" :
"[email protected] " },
321
+ follow_redirects = False
322
+ )
323
+
324
+ assert response .status_code == 303 # Redirect to login
325
+
326
+
327
+ def test_confirm_email_update_success (unauth_client : TestClient , session : Session , test_user : User ):
328
+ """Test successful email update confirmation"""
329
+
330
+
331
+ # Create an email update token
332
+ update_token = EmailUpdateToken (user_id = test_user .id )
333
+ session .add (update_token )
334
+ session .commit ()
335
+
336
+ response = unauth_client .get (
337
+ app .url_path_for ("confirm_email_update" ),
338
+ params = {
339
+ "user_id" : test_user .id ,
340
+ "token" : update_token .token ,
341
+ "new_email" : new_email
342
+ },
343
+ follow_redirects = False
344
+ )
345
+
346
+ assert response .status_code == 303
347
+ assert "profile?email_updated=true" in response .headers ["location" ]
348
+
349
+ # Verify email was updated
350
+ session .refresh (test_user )
351
+ assert test_user .email == new_email
352
+
353
+ # Verify token was marked as used
354
+ session .refresh (update_token )
355
+ assert update_token .used
356
+
357
+ # Verify new auth cookies were set
358
+ cookies = response .cookies
359
+ assert "access_token" in cookies
360
+ assert "refresh_token" in cookies
361
+
362
+
363
+ def test_confirm_email_update_invalid_token (unauth_client : TestClient , session : Session , test_user : User ):
364
+ """Test email update confirmation with invalid token"""
365
+ response = unauth_client .get (
366
+ app .url_path_for ("confirm_email_update" ),
367
+ params = {
368
+ "user_id" : test_user .id ,
369
+ "token" : "invalid_token" ,
370
+
371
+ }
372
+ )
373
+
374
+ assert response .status_code == 401
375
+ assert "Invalid or expired" in response .text
376
+
377
+ # Verify email was not updated
378
+ session .refresh (test_user )
379
+ assert test_user .
email == "[email protected] "
380
+
381
+
382
+ def test_confirm_email_update_used_token (unauth_client : TestClient , session : Session , test_user : User ):
383
+ """Test email update confirmation with already used token"""
384
+ # Create an already used token
385
+ used_token = PasswordResetToken (
386
+ user_id = test_user .id ,
387
+ token = "test_used_token" ,
388
+ used = True ,
389
+ token_type = "email_update"
390
+ )
391
+ session .add (used_token )
392
+ session .commit ()
393
+
394
+ response = unauth_client .get (
395
+ app .url_path_for ("confirm_email_update" ),
396
+ params = {
397
+ "user_id" : test_user .id ,
398
+ "token" : used_token .token ,
399
+
400
+ }
401
+ )
402
+
403
+ assert response .status_code == 401
404
+ assert "Invalid or expired" in response .text
405
+
406
+ # Verify email was not updated
407
+ session .refresh (test_user )
408
+ assert test_user .
email == "[email protected] "
0 commit comments