Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lms/djangoapps/instructor/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,10 @@ def test_list_course_role_members_staff(self):
'first_name': self.other_staff.first_name,
'last_name': self.other_staff.last_name,
}
]
],
'count': 1,
'num_pages': 1,
'current_page': 1,
}
res_json = json.loads(response.content.decode('utf-8'))
assert res_json == expected
Expand All @@ -2440,7 +2443,10 @@ def test_list_course_role_members_beta(self):
# check response content
expected = {
'course_id': str(self.course.id),
'beta': []
'beta': [],
'count': 0,
'num_pages': 0,
'current_page': 1,
}
res_json = json.loads(response.content.decode('utf-8'))
assert res_json == expected
Expand Down
302 changes: 301 additions & 1 deletion lms/djangoapps/instructor/tests/test_api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from rest_framework.test import APIClient, APITestCase

from edx_when.api import set_dates_for_course, set_date_for_block
from common.djangoapps.student.roles import CourseDataResearcherRole, CourseInstructorRole
from common.djangoapps.student.roles import CourseBetaTesterRole, CourseDataResearcherRole, CourseInstructorRole
from common.djangoapps.student.tests.factories import (
AdminFactory,
CourseEnrollmentFactory,
Expand Down Expand Up @@ -1734,3 +1734,303 @@ def test_extension_data_structure(self, mock_title_or_url, mock_get_units, mock_
self.assertIsInstance(extension['email'], str)
self.assertIsInstance(extension['unit_title'], str)
self.assertIsInstance(extension['unit_location'], str)


class CourseEnrollmentsViewTest(SharedModuleStoreTestCase):
"""Tests for the CourseEnrollmentsView v2 GET endpoint."""

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course = CourseFactory.create()

def setUp(self):
super().setUp()
self.client = APIClient()
self.instructor = InstructorFactory(course_key=self.course.id)
self.url = reverse(
'instructor_api_v2:course_enrollments',
kwargs={'course_id': str(self.course.id)}
)

self.enrolled_users = []
for i in range(30):
user = UserFactory(
username=f'student_{i}',
email=f'student{i}@example.com',
first_name=f'Student{i}',
last_name=f'Learner{i}'
)
CourseEnrollmentFactory(
user=user,
course_id=self.course.id,
is_active=True
)
self.enrolled_users.append(user)

# Inactive enrollments should not appear
for i in range(5):
user = UserFactory(
username=f'inactive_{i}',
email=f'inactive{i}@example.com'
)
CourseEnrollmentFactory(
user=user,
course_id=self.course.id,
is_active=False
)

def test_unauthenticated_returns_401(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_student_returns_403(self):
student = UserFactory()
self.client.force_authenticate(user=student)
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_default_pagination(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
data = response.data
self.assertEqual(data['course_id'], str(self.course.id))
self.assertEqual(data['count'], 30)
self.assertEqual(data['num_pages'], 2)
self.assertEqual(data['current_page'], 1)
self.assertEqual(len(data['enrollments']), 20)

def test_custom_pagination(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page': 1, 'page_size': 10})
data = response.data
self.assertEqual(data['count'], 30)
self.assertEqual(data['num_pages'], 3)
self.assertEqual(len(data['enrollments']), 10)

def test_second_page(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page': 2, 'page_size': 10})
data = response.data
self.assertEqual(data['current_page'], 2)
self.assertEqual(len(data['enrollments']), 10)

def test_last_page_partial(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page': 3, 'page_size': 10})
data = response.data
self.assertEqual(data['current_page'], 3)
self.assertEqual(len(data['enrollments']), 10)

def test_search_by_username(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': 'student_2', 'page_size': 100})
data = response.data
# Matches student_2, student_20..student_29 = 11
self.assertEqual(data['count'], 11)
for user in data['enrollments']:
self.assertIn('student_2', user['username'])

def test_search_by_email(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': 'student7@example.com'})
data = response.data
self.assertEqual(data['count'], 1)
self.assertEqual(data['enrollments'][0]['email'], 'student7@example.com')

def test_search_case_insensitive(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': 'STUDENT_5'})
data = response.data
self.assertEqual(data['count'], 1)
self.assertEqual(data['enrollments'][0]['username'], 'student_5')

def test_search_no_results(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': 'nonexistent'})
data = response.data
self.assertEqual(data['count'], 0)
self.assertEqual(len(data['enrollments']), 0)

def test_excludes_inactive_enrollments(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': 'inactive'})
data = response.data
self.assertEqual(data['count'], 0)

def test_invalid_page_size(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page_size': 0})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_invalid_page(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page': -1})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_ordered_by_username(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page_size': 5})
data = response.data
usernames = [u['username'] for u in data['enrollments']]
self.assertEqual(usernames, sorted(usernames))

def test_staff_can_access(self):
staff = StaffFactory(course_key=self.course.id)
self.client.force_authenticate(user=staff)
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_includes_mode_field(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page_size': 1})
enrollment = response.data['enrollments'][0]
self.assertIn('mode', enrollment)

def test_includes_is_beta_tester_field(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'page_size': 100})
for enrollment in response.data['enrollments']:
self.assertIn('is_beta_tester', enrollment)
self.assertFalse(enrollment['is_beta_tester'])

def test_beta_tester_flag_true(self):
beta_role = CourseBetaTesterRole(self.course.id)
target_user = self.enrolled_users[0]
beta_role.add_users(target_user)

self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'search': target_user.username})
data = response.data
self.assertEqual(data['count'], 1)
self.assertTrue(data['enrollments'][0]['is_beta_tester'])


class RoleMembersViewTest(SharedModuleStoreTestCase):
"""Tests for the RoleMembersView v2 GET endpoint."""

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course = CourseFactory.create()

def setUp(self):
super().setUp()
self.client = APIClient()
self.instructor = InstructorFactory(course_key=self.course.id)
self.url = reverse(
'instructor_api_v2:role_members',
kwargs={'course_id': str(self.course.id)}
)

self.beta_testers = []
beta_role = CourseBetaTesterRole(self.course.id)
for i in range(25):
user = UserFactory(
username=f'beta_user_{i}',
email=f'beta{i}@example.com',
first_name=f'Beta{i}',
last_name=f'Tester{i}'
)
beta_role.add_users(user)
self.beta_testers.append(user)

def test_unauthenticated_returns_401(self):
response = self.client.get(self.url, {'rolename': 'beta'})
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_student_returns_403(self):
student = UserFactory()
self.client.force_authenticate(user=student)
response = self.client.get(self.url, {'rolename': 'beta'})
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_missing_rolename_returns_400(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_invalid_rolename_returns_400(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'invalid_role'})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_list_beta_testers_default_pagination(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta'})
self.assertEqual(response.status_code, status.HTTP_200_OK)
data = response.data
self.assertEqual(data['course_id'], str(self.course.id))
self.assertIn('beta', data)
self.assertEqual(data['count'], 25)
self.assertEqual(data['num_pages'], 2)
self.assertEqual(data['current_page'], 1)
self.assertEqual(len(data['beta']), 20)

def test_list_beta_testers_custom_pagination(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'page': 1, 'page_size': 10})
data = response.data
self.assertEqual(data['count'], 25)
self.assertEqual(data['num_pages'], 3)
self.assertEqual(len(data['beta']), 10)

def test_list_beta_testers_last_page(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'page': 3, 'page_size': 10})
data = response.data
self.assertEqual(data['current_page'], 3)
self.assertEqual(len(data['beta']), 5)

def test_beyond_last_page_empty(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'page': 10, 'page_size': 10})
data = response.data
self.assertEqual(len(data['beta']), 0)

def test_search_by_username(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'search': 'beta_user_1', 'page_size': 100})
data = response.data
# Matches beta_user_1, beta_user_10..beta_user_19 = 11
self.assertEqual(data['count'], 11)
for user in data['beta']:
self.assertIn('beta_user_1', user['username'])

def test_search_by_email(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'search': 'beta5@example.com'})
data = response.data
self.assertEqual(data['count'], 1)
self.assertEqual(data['beta'][0]['email'], 'beta5@example.com')

def test_search_case_insensitive(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'search': 'BETA_USER_3'})
data = response.data
self.assertEqual(data['count'], 1)
self.assertEqual(data['beta'][0]['username'], 'beta_user_3')

def test_search_no_results(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'search': 'nonexistent'})
data = response.data
self.assertEqual(data['count'], 0)
self.assertEqual(len(data['beta']), 0)

def test_list_staff_role(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'staff'})
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('staff', response.data)

def test_invalid_page_size(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'page_size': 0})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_invalid_page(self):
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self.url, {'rolename': 'beta', 'page': 0})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Loading
Loading