Split backend tests into unit and integration suites, add isolated fixtures and coverage enforcement, and update CI and test documentation. Cover current authentication, content, notification, payment, media, and admin flows; fix behaviors revealed by the new tests. Validate both suites and the per-module gate against local PostgreSQL.
73 lines
3.7 KiB
Python
73 lines
3.7 KiB
Python
import pytest
|
|
import json
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from apps.users.models import User
|
|
from core.authentication import create_jwt_token
|
|
|
|
@pytest.mark.django_db
|
|
@pytest.mark.integration
|
|
class TestUsersAPIIntegrationTests:
|
|
|
|
def setup_method(self):
|
|
self.user = User.objects.create_user(username='mobile_user', mobile='09192000001', email='person@example.com', password='Sup3rSecure!123', is_mobile_verified=True)
|
|
|
|
def _auth(self):
|
|
return {'HTTP_AUTHORIZATION': f'Bearer {create_jwt_token(self.user)}'}
|
|
|
|
def test_password_login_accepts_mobile_identity(self):
|
|
response = self.client.post('/api/auth/login', json.dumps({'identifier': self.user.mobile, 'password': 'Sup3rSecure!123'}), content_type='application/json')
|
|
assert response.status_code == 200
|
|
assert 'access_token' in response.json()
|
|
|
|
def test_profile_update_treats_supplied_email_as_identity(self):
|
|
response = self.client.put('/api/auth/profile', json.dumps({'email': 'new@example.com'}), content_type='application/json', **self._auth())
|
|
assert response.status_code == 200
|
|
self.user.refresh_from_db()
|
|
assert self.user.email == 'new@example.com'
|
|
assert self.user.is_email_verified
|
|
|
|
def test_profile_update_clears_email_identity_flag(self):
|
|
response = self.client.put('/api/auth/profile', json.dumps({'email': ''}), content_type='application/json', **self._auth())
|
|
assert response.status_code == 200
|
|
self.user.refresh_from_db()
|
|
assert self.user.email is None
|
|
assert not self.user.is_email_verified
|
|
|
|
def test_profile_requires_authentication_and_returns_account_identity(self):
|
|
assert self.client.get('/api/auth/profile').status_code == 401
|
|
response = self.client.get('/api/auth/profile', **self._auth())
|
|
assert response.status_code == 200
|
|
assert response.json()['mobile'] == self.user.mobile
|
|
|
|
def test_profile_rejects_duplicate_email(self):
|
|
User.objects.create_user(username='second', mobile='09192000002', email='taken@example.com', password='password')
|
|
response = self.client.put('/api/auth/profile', json.dumps({'email': 'taken@example.com'}), content_type='application/json', **self._auth())
|
|
assert response.status_code == 400
|
|
self.user.refresh_from_db()
|
|
assert self.user.email == 'person@example.com'
|
|
|
|
def test_profile_picture_rejects_non_image_upload(self):
|
|
image = SimpleUploadedFile('notes.txt', b'not an image', content_type='text/plain')
|
|
response = self.client.post('/api/auth/profile/picture', {'file': image}, **self._auth())
|
|
assert response.status_code == 400
|
|
|
|
def test_check_username_reports_existing_user(self):
|
|
response = self.client.get('/api/auth/check-username', {'username': self.user.username})
|
|
assert response.status_code == 200
|
|
assert response.json()['exists']
|
|
|
|
def test_legacy_email_auth_routes_are_gone(self):
|
|
assert self.client.get('/api/auth/verify-email/token').status_code == 404
|
|
assert self.client.post('/api/auth/resend-verification').status_code == 404
|
|
assert self.client.post('/api/auth/request-password-reset').status_code == 404
|
|
|
|
def test_mobile_otp_password_reset_route_remains_available(self, mocker):
|
|
reset = mocker.patch('apps.users.api.views.reset_password_with_otp')
|
|
response = self.client.post('/api/auth/reset-password', json.dumps({'mobile': self.user.mobile, 'code': '123456', 'new_password': 'AnotherSecurePass!123'}), content_type='application/json')
|
|
assert response.status_code == 200
|
|
reset.assert_called_once()
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _pytest_client(self, client):
|
|
self.client = client
|