- إضافة نقاط نهاية لخاصيتي استعادة كلمة المرور وإعادة تعيينها في الواجهة الخلفية. - إنشاء اختبارات لخاصية إعادة تعيين كلمة المرور لضمان كفاءتها وأمانها. - تطوير صفحات واجهة المستخدم لخاصيتي استعادة كلمة المرور وإعادة تعيينها مع معالجة النماذج. - دمج حدود تحميل ديناميكية لأنواع ملفات مختلفة بناءً على خطط المستخدمين. - تقديم أداة جديدة لتغيير حجم الصور مع إمكانية تعديل الأبعاد وإعدادات الجودة. - تحديث نظام التوجيه والتنقل ليشمل أدوات جديدة وميزات مصادقة. - تحسين تجربة المستخدم من خلال معالجة الأخطاء ورسائل التغذية الراجعة المناسبة. - إضافة دعم التدويل للميزات الجديدة باللغات الإنجليزية والعربية والفرنسية.
133 lines
4.7 KiB
Python
133 lines
4.7 KiB
Python
"""Tests for forgot-password and reset-password endpoints."""
|
|
import pytest
|
|
from unittest.mock import patch
|
|
|
|
|
|
class TestForgotPassword:
|
|
"""Tests for POST /api/auth/forgot-password."""
|
|
|
|
def test_forgot_password_returns_200_for_unknown_email(self, client):
|
|
"""Should always return 200 to avoid leaking registration info."""
|
|
resp = client.post("/api/auth/forgot-password", json={
|
|
"email": "doesnotexist@example.com",
|
|
})
|
|
assert resp.status_code == 200
|
|
assert "message" in resp.get_json()
|
|
|
|
def test_forgot_password_returns_200_for_registered_email(self, client):
|
|
"""Should return 200 and trigger email sending."""
|
|
client.post("/api/auth/register", json={
|
|
"email": "reset_user@example.com",
|
|
"password": "TestPassword123!",
|
|
})
|
|
client.post("/api/auth/logout")
|
|
|
|
with patch("app.routes.auth.send_password_reset_email") as mock_send:
|
|
mock_send.return_value = True
|
|
resp = client.post("/api/auth/forgot-password", json={
|
|
"email": "reset_user@example.com",
|
|
})
|
|
assert resp.status_code == 200
|
|
mock_send.assert_called_once()
|
|
|
|
def test_forgot_password_bad_email_format(self, client):
|
|
"""Still returns 200 even for bad email format (no info leak)."""
|
|
resp = client.post("/api/auth/forgot-password", json={
|
|
"email": "not-an-email",
|
|
})
|
|
assert resp.status_code == 200
|
|
|
|
|
|
class TestResetPassword:
|
|
"""Tests for POST /api/auth/reset-password."""
|
|
|
|
def test_reset_password_missing_token(self, client):
|
|
"""Should reject when token is empty."""
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": "",
|
|
"password": "NewPassword123!",
|
|
})
|
|
assert resp.status_code == 400
|
|
|
|
def test_reset_password_invalid_token(self, client):
|
|
"""Should reject unknown token."""
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": "totally-invalid-token",
|
|
"password": "NewPassword123!",
|
|
})
|
|
assert resp.status_code == 400
|
|
|
|
def test_reset_password_short_password(self, client):
|
|
"""Should reject short passwords."""
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": "some-token",
|
|
"password": "short",
|
|
})
|
|
assert resp.status_code == 400
|
|
|
|
def test_reset_password_full_flow(self, client, app):
|
|
"""Register → forgot → get token → reset → login with new password."""
|
|
# Register
|
|
client.post("/api/auth/register", json={
|
|
"email": "fullreset@example.com",
|
|
"password": "OldPassword123!",
|
|
})
|
|
client.post("/api/auth/logout")
|
|
|
|
# Create reset token directly
|
|
from app.services.account_service import get_user_by_email, create_password_reset_token
|
|
|
|
with app.app_context():
|
|
user = get_user_by_email("fullreset@example.com")
|
|
token = create_password_reset_token(user["id"])
|
|
|
|
# Reset
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": token,
|
|
"password": "NewPassword123!",
|
|
})
|
|
assert resp.status_code == 200
|
|
|
|
# Login with new password
|
|
resp = client.post("/api/auth/login", json={
|
|
"email": "fullreset@example.com",
|
|
"password": "NewPassword123!",
|
|
})
|
|
assert resp.status_code == 200
|
|
|
|
# Old password should fail
|
|
client.post("/api/auth/logout")
|
|
resp = client.post("/api/auth/login", json={
|
|
"email": "fullreset@example.com",
|
|
"password": "OldPassword123!",
|
|
})
|
|
assert resp.status_code == 401
|
|
|
|
def test_reset_token_cannot_be_reused(self, client, app):
|
|
"""A reset token should be consumed on use and fail on second use."""
|
|
client.post("/api/auth/register", json={
|
|
"email": "reuse@example.com",
|
|
"password": "OldPassword123!",
|
|
})
|
|
client.post("/api/auth/logout")
|
|
|
|
from app.services.account_service import get_user_by_email, create_password_reset_token
|
|
|
|
with app.app_context():
|
|
user = get_user_by_email("reuse@example.com")
|
|
token = create_password_reset_token(user["id"])
|
|
|
|
# First use — should succeed
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": token,
|
|
"password": "NewPassword123!",
|
|
})
|
|
assert resp.status_code == 200
|
|
|
|
# Second use — should fail
|
|
resp = client.post("/api/auth/reset-password", json={
|
|
"token": token,
|
|
"password": "AnotherPassword123!",
|
|
})
|
|
assert resp.status_code == 400
|