diff --git a/backend/tests/test_comments.py b/backend/tests/test_comments.py index a891cb0..924fb33 100644 --- a/backend/tests/test_comments.py +++ b/backend/tests/test_comments.py @@ -15,7 +15,7 @@ """ import pytest -from rest_framework.test import APIClient +from rest_framework.test import APIClient, APITestCase from django.contrib.auth import get_user_model from django.urls import reverse from workouts.models import Workout @@ -24,6 +24,8 @@ from django.test import TestCase from rest_framework import status +User = get_user_model() + @pytest.mark.django_db class TestCommentSubmission(APITestCase): """ @@ -40,10 +42,9 @@ class TestCommentSubmission(APITestCase): def setUp(self): """Set up test data and URLs.""" self.client = APIClient() - self.url = reverse('comment-list') + self.comment_list_url = reverse('comment-list') # Create a test user - User = get_user_model() self.user = User.objects.create_user( username='testuser', email='test@example.com', @@ -63,7 +64,7 @@ def setUp(self): self.client.force_authenticate(user=self.user) self.comment_data = { 'content': 'Test comment', - 'workout': self.workout.id + 'workout': reverse('workout-detail', args=[self.workout.id]) } def test_valid_comment_submission(self): @@ -75,10 +76,11 @@ def test_valid_comment_submission(self): - Comment is created in database - Response contains comment data with correct associations """ - response = self.client.post(self.url, self.comment_data) + response = self.client.post(self.comment_list_url, self.comment_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertTrue(Comment.objects.filter(content='Test comment').exists()) - self.assertEqual(response.data['workout'], self.workout.id) + expected_url = 'http://testserver' + reverse('workout-detail', args=[self.workout.id]) + self.assertEqual(response.data['workout'], expected_url) def test_invalid_comment_submission_empty_content(self): """ @@ -90,7 +92,7 @@ def test_invalid_comment_submission_empty_content(self): """ data = self.comment_data.copy() data['content'] = '' - response = self.client.post(self.url, data) + response = self.client.post(self.comment_list_url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('content', response.data) @@ -104,7 +106,7 @@ def test_invalid_comment_submission_no_workout(self): """ data = self.comment_data.copy() del data['workout'] - response = self.client.post(self.url, data) + response = self.client.post(self.comment_list_url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('workout', response.data) @@ -116,14 +118,21 @@ def test_comment_submission_on_private_workout(self): - 403 Forbidden status code - Error message about insufficient permissions """ + # Create another user who owns the private workout + other_user = User.objects.create_user( + username='otheruser', + email='other@example.com', + password='ValidPass123!' + ) + private_workout = Workout.objects.create( name="Private Workout", date=datetime.now(), notes="Private notes", - owner=self.user, + owner=other_user, # Set the other user as the owner visibility="PR" ) data = self.comment_data.copy() - data['workout'] = private_workout.id - response = self.client.post(self.url, data) + data['workout'] = reverse('workout-detail', args=[private_workout.id]) + response = self.client.post(self.comment_list_url, data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) \ No newline at end of file diff --git a/backend/tests/test_media.py b/backend/tests/test_media.py index ec7cbb6..373a07f 100644 --- a/backend/tests/test_media.py +++ b/backend/tests/test_media.py @@ -15,7 +15,7 @@ """ import pytest -from rest_framework.test import APIClient +from rest_framework.test import APIClient, APITestCase from django.contrib.auth import get_user_model from django.urls import reverse from workouts.models import Workout, WorkoutFile @@ -24,60 +24,47 @@ import os from django.test import TestCase from rest_framework import status +from users.models import User +from django.conf import settings @pytest.mark.django_db class TestMediaUpload(APITestCase): - """ - Test cases for media upload endpoints. - - Tests cover: - - Successful file uploads - - File size restrictions - - File type validation - - Owner permissions - - Access control for private workouts - """ - def setUp(self): - """Set up test data and URLs.""" + """Set up test data and client.""" self.client = APIClient() - self.url = reverse('workout-file-list') - - # Create a test user - User = get_user_model() self.user = User.objects.create_user( username='testuser', - email='test@example.com', - password='ValidPass123!' + password='testpass123' ) + self.client.force_authenticate(user=self.user) - # Create a test workout self.workout = Workout.objects.create( - name="Test Workout", - date=datetime.now(), - notes="Test notes", + name='Test Workout', owner=self.user, - visibility="CO" + date='2025-04-02', + visibility='CO' ) - # Authenticate the client - self.client.force_authenticate(user=self.user) - + # Create test files self.test_file = SimpleUploadedFile( - "test.txt", - b"test content", - content_type="text/plain" + "test.jpg", + b"file_content", + content_type="image/jpeg" ) + self.large_file = SimpleUploadedFile( - "large.txt", - b"x" * (6 * 1024 * 1024), # 6MB file - content_type="text/plain" + "large.jpg", + b"x" * (5 * 1024 * 1024 + 1), # 5MB + 1 byte + content_type="image/jpeg" ) + self.invalid_file = SimpleUploadedFile( - "test.exe", - b"test content", - content_type="application/x-msdownload" + "test.txt", + b"file_content", + content_type="text/plain" ) + + self.upload_url = reverse('workout-file-list') def test_valid_media_upload(self): """ @@ -90,12 +77,12 @@ def test_valid_media_upload(self): """ data = { 'file': self.test_file, - 'workout': self.workout.id + 'workout': reverse('workout-detail', args=[self.workout.id]) } - response = self.client.post(self.url, data, format='multipart') - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertTrue(WorkoutFile.objects.filter(workout=self.workout).exists()) - self.assertIn('file', response.data) + response = self.client.post(self.upload_url, data, format='multipart') + assert response.status_code == status.HTTP_201_CREATED + assert WorkoutFile.objects.filter(workout=self.workout).exists() + assert 'file' in response.data def test_invalid_media_upload_no_file(self): """ @@ -105,10 +92,10 @@ def test_invalid_media_upload_no_file(self): - 400 Bad Request status code - Error message about missing file """ - data = {'workout': self.workout.id} - response = self.client.post(self.url, data, format='multipart') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('file', response.data) + data = {'workout': reverse('workout-detail', args=[self.workout.id])} + response = self.client.post(self.upload_url, data, format='multipart') + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'file' in response.data def test_invalid_media_upload_large_file(self): """ @@ -120,11 +107,11 @@ def test_invalid_media_upload_large_file(self): """ data = { 'file': self.large_file, - 'workout': self.workout.id + 'workout': reverse('workout-detail', args=[self.workout.id]) } - response = self.client.post(self.url, data, format='multipart') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('file', response.data) + response = self.client.post(self.upload_url, data, format='multipart') + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'file' in response.data def test_invalid_media_upload_wrong_owner(self): """ @@ -136,22 +123,19 @@ def test_invalid_media_upload_wrong_owner(self): """ other_user = get_user_model().objects.create_user( username='otheruser', - email='other@example.com', - password='ValidPass123!' + password='TestPass123!' ) other_workout = Workout.objects.create( - name="Other Workout", - date=datetime.now(), - notes="Other notes", owner=other_user, - visibility="CO" + name='Other Workout', + date='2025-04-02' ) data = { 'file': self.test_file, - 'workout': other_workout.id + 'workout': reverse('workout-detail', args=[other_workout.id]) } - response = self.client.post(self.url, data, format='multipart') - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + response = self.client.post(self.upload_url, data, format='multipart') + assert response.status_code == status.HTTP_403_FORBIDDEN def test_invalid_media_upload_extension(self): """ @@ -163,8 +147,8 @@ def test_invalid_media_upload_extension(self): """ data = { 'file': self.invalid_file, - 'workout': self.workout.id + 'workout': reverse('workout-detail', args=[self.workout.id]) } - response = self.client.post(self.url, data, format='multipart') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('file', response.data) \ No newline at end of file + response = self.client.post(self.upload_url, data, format='multipart') + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'file' in response.data \ No newline at end of file diff --git a/backend/tests/test_users.py b/backend/tests/test_users.py index 49b5220..d48a9ca 100644 --- a/backend/tests/test_users.py +++ b/backend/tests/test_users.py @@ -18,23 +18,11 @@ from rest_framework.test import APIClient from django.contrib.auth import get_user_model from django.urls import reverse -from django.test import TestCase from rest_framework import status @pytest.mark.django_db -class TestUserRegistration(APITestCase): - """ - Test cases for user registration endpoint. - - Tests cover: - - Successful registration for both athletes and coaches - - Validation of required fields - - Password requirements and validation - - Specialism field handling for coaches - - Error handling for invalid inputs - """ - - def setUp(self): +class TestUserRegistration: + def setup_method(self): """Set up test data and URLs.""" self.client = APIClient() self.register_url = reverse('user-register') @@ -42,7 +30,7 @@ def setUp(self): 'username': 'testuser', 'email': 'test@example.com', 'password': 'TestPass123!', - 'password2': 'TestPass123!', + 'password1': 'TestPass123!', 'isCoach': False, 'specialism': '' } @@ -57,9 +45,9 @@ def test_valid_user_registration(self): - Response contains user data (excluding password) """ response = self.client.post(self.register_url, self.user_data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertTrue(get_user_model().objects.filter(username="testuser").exists()) - self.assertNotIn('password', response.data) + assert response.status_code == status.HTTP_201_CREATED + assert get_user_model().objects.filter(username="testuser").exists() + assert 'password' not in response.data def test_invalid_user_registration_missing_username(self): """ @@ -72,8 +60,8 @@ def test_invalid_user_registration_missing_username(self): data = self.user_data.copy() del data['username'] response = self.client.post(self.register_url, data) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('username', response.data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'username' in response.data def test_invalid_user_registration_password_mismatch(self): """ @@ -84,10 +72,10 @@ def test_invalid_user_registration_password_mismatch(self): - Error message about password mismatch """ data = self.user_data.copy() - data['password2'] = 'DifferentPass123!' + data['password1'] = 'DifferentPass123!' response = self.client.post(self.register_url, data) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('password', response.data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'password' in response.data def test_invalid_user_registration_weak_password(self): """ @@ -99,7 +87,7 @@ def test_invalid_user_registration_weak_password(self): """ data = self.user_data.copy() data['password'] = 'weak' - data['password2'] = 'weak' + data['password1'] = 'weak' response = self.client.post(self.register_url, data) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('password', response.data) \ No newline at end of file + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'password' in response.data \ No newline at end of file diff --git a/backend/tests/test_workouts.py b/backend/tests/test_workouts.py index 5fb09b0..8b11a53 100644 --- a/backend/tests/test_workouts.py +++ b/backend/tests/test_workouts.py @@ -2,11 +2,11 @@ Test suite for workout management functionality. This module contains tests that verify: -1. Workout creation with valid and invalid data -2. Workout editing and updates -3. Workout visibility and access control -4. Date validation and formatting -5. Owner permissions and restrictions +1. Workout creation +2. Workout editing +3. Workout visibility +4. Owner permissions +5. Access control for private workouts Each test case includes: - Setup: Required data and conditions @@ -15,42 +15,47 @@ """ import pytest -from rest_framework.test import APIClient +from rest_framework.test import APIClient, APITestCase from django.contrib.auth import get_user_model from django.urls import reverse from workouts.models import Workout, Exercise, ExerciseInstance from datetime import datetime, timedelta from django.test import TestCase from rest_framework import status +from users.models import User @pytest.mark.django_db class TestWorkoutManagement(APITestCase): - """ - Test cases for workout management endpoints. - - Tests cover: - - Workout creation with valid data - - Input validation for required fields - - Date format validation - - Workout editing functionality - - Visibility and access control - - Owner permissions - """ - def setUp(self): - """Set up test data and URLs.""" - self.user = get_user_model().objects.create_user( + """Set up test data and client.""" + self.client = APIClient() + self.user = User.objects.create_user( username='testuser', - password='TestPass123!' + password='testpass123' ) self.client.force_authenticate(user=self.user) - self.workout_list_url = reverse('workout-list') + + # Create test exercise + self.exercise = Exercise.objects.create( + name='Test Exercise', + description='Test Description', + unit='reps' + ) + self.workout_data = { 'name': 'Test Workout', - 'description': 'Test Description', 'date': '2025-04-02', - 'isPublic': True + 'notes': 'Test notes', + 'visibility': 'CO', + 'exercise_instances': [ + { + 'exercise': reverse('exercise-detail', args=[self.exercise.id]), + 'sets': 3, + 'number': 10 + } + ] } + self.workout_list_url = reverse('workout-list') def test_valid_workout_creation(self): """ @@ -61,10 +66,11 @@ def test_valid_workout_creation(self): - Workout is created in database - Response contains workout data with correct owner """ - response = self.client.post(self.workout_list_url, self.workout_data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertTrue(Workout.objects.filter(name="Test Workout").exists()) - self.assertEqual(response.data['owner'], self.user.id) + response = self.client.post(self.workout_list_url, self.workout_data, format='json') + print("Response data:", response.data) + assert response.status_code == status.HTTP_201_CREATED + assert Workout.objects.filter(owner=self.user).exists() + assert response.data['owner'] == self.user.id def test_workout_creation_empty_name(self): """ @@ -77,8 +83,8 @@ def test_workout_creation_empty_name(self): data = self.workout_data.copy() data['name'] = '' response = self.client.post(self.workout_list_url, data) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('name', response.data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'name' in response.data def test_workout_creation_invalid_date(self): """ @@ -91,8 +97,8 @@ def test_workout_creation_invalid_date(self): data = self.workout_data.copy() data['date'] = 'invalid-date' response = self.client.post(self.workout_list_url, data) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('date', response.data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'date' in response.data def test_workout_editing(self): """ @@ -106,17 +112,18 @@ def test_workout_editing(self): workout = Workout.objects.create( owner=self.user, name='Original Name', - date='2025-04-02' + date='2025-04-02', + visibility='CO' ) update_data = {'name': 'Updated Name'} response = self.client.patch( reverse('workout-detail', kwargs={'pk': workout.pk}), update_data ) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], 'Updated Name') + assert response.status_code == status.HTTP_200_OK + assert response.data['name'] == 'Updated Name' workout.refresh_from_db() - self.assertEqual(workout.name, 'Updated Name') + assert workout.name == 'Updated Name' def test_viewing_public_workout(self): """ @@ -135,11 +142,11 @@ def test_viewing_public_workout(self): owner=other_user, name='Public Workout', date='2025-04-02', - isPublic=True + visibility='PU' ) response = self.client.get( reverse('workout-detail', kwargs={'pk': workout.pk}) ) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], 'Public Workout') - self.assertEqual(response.data['owner'], other_user.id) \ No newline at end of file + assert response.status_code == status.HTTP_200_OK + assert response.data['owner'] == other_user.id + assert response.data['name'] == 'Public Workout' \ No newline at end of file