Files
Salon/backend/apps/accounts/tests/test_phone_first_enforcement.py
T
2026-03-13 23:48:40 +03:00

72 lines
2.2 KiB
Python

from unittest.mock import patch
import pytest
from django.urls import reverse
from apps.accounts.models import OtpPurpose, PhoneOTP, User
@pytest.mark.django_db
def test_create_user_rejects_email_only_identity():
# Phone-first invariant: do not allow creating users without phone_number.
with pytest.raises(ValueError):
User.objects.create_user(email="email-only@example.com")
@pytest.mark.django_db
def test_register_requires_phone_number(client):
# Public registration must keep phone as required identifier.
response = client.post(
reverse("register"),
{"email": "new@example.com", "password": "StrongPass123"},
content_type="application/json",
)
assert response.status_code == 400
assert "phone_number" in response.json()
@pytest.mark.django_db
def test_phone_auth_verify_rejects_verify_purpose_otp(client):
user = User.objects.create_user(phone_number="+966512345678")
otp = PhoneOTP.objects.create(
phone_number=user.phone_number,
channel="sms",
purpose=OtpPurpose.VERIFY,
provider="console",
code_hash="not-used",
expires_at=PhoneOTP.expiry_at(),
)
# Purpose boundary: /phone/verify must only accept auth OTP requests.
with patch("apps.accounts.views.verify_otp", return_value=True):
response = client.post(
reverse("phone_auth_verify"),
{"request_id": str(otp.id), "code": "123456"},
content_type="application/json",
)
assert response.status_code == 400
@pytest.mark.django_db
def test_otp_verify_rejects_auth_purpose_otp(client):
otp = PhoneOTP.objects.create(
phone_number="+966512345678",
channel="sms",
purpose=OtpPurpose.AUTH,
provider="console",
code_hash="not-used",
expires_at=PhoneOTP.expiry_at(),
)
# Purpose boundary: /otp/verify must only accept verify OTP requests.
with patch("apps.accounts.views.verify_otp", return_value=True):
response = client.post(
reverse("otp_verify"),
{"request_id": str(otp.id), "code": "123456"},
content_type="application/json",
)
assert response.status_code == 400