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