Commit 4316731f by attiyaishaque

TNL-4412 user is not enrolled as a beta tester when account is unactivated.

parent b06d5bed
...@@ -18,7 +18,7 @@ class AutoAuthPage(PageObject): ...@@ -18,7 +18,7 @@ class AutoAuthPage(PageObject):
CONTENT_REGEX = r'.+? user (?P<username>\S+) \((?P<email>.+?)\) with password \S+ and user_id (?P<user_id>\d+)$' CONTENT_REGEX = r'.+? user (?P<username>\S+) \((?P<email>.+?)\) with password \S+ and user_id (?P<user_id>\d+)$'
def __init__(self, browser, username=None, email=None, password=None, full_name=None, staff=None, course_id=None, def __init__(self, browser, username=None, email=None, password=None, full_name=None, staff=None, course_id=None,
enrollment_mode=None, roles=None): enrollment_mode=None, roles=None, is_active=None):
""" """
Auto-auth is an end-point for HTTP GET requests. Auto-auth is an end-point for HTTP GET requests.
By default, it will create accounts with random user credentials, By default, it will create accounts with random user credentials,
...@@ -62,6 +62,9 @@ class AutoAuthPage(PageObject): ...@@ -62,6 +62,9 @@ class AutoAuthPage(PageObject):
if roles is not None: if roles is not None:
self._params['roles'] = roles self._params['roles'] = roles
if is_active is not None:
self._params['is_active'] = "true" if is_active else "false"
@property @property
def url(self): def url(self):
""" """
......
...@@ -194,6 +194,12 @@ class MembershipPage(PageObject): ...@@ -194,6 +194,12 @@ class MembershipPage(PageObject):
""" """
return MembershipPageAutoEnrollSection(self.browser) return MembershipPageAutoEnrollSection(self.browser)
def batch_beta_tester_addition(self):
"""
Returns the MembershipPageBetaTesterSection page object.
"""
return MembershipPageBetaTesterSection(self.browser)
class SpecialExamsPage(PageObject): class SpecialExamsPage(PageObject):
""" """
...@@ -880,6 +886,44 @@ class MembershipPageAutoEnrollSection(PageObject): ...@@ -880,6 +886,44 @@ class MembershipPageAutoEnrollSection(PageObject):
return self.q(css="{} h3".format(notification_selector)).text return self.q(css="{} h3".format(notification_selector)).text
class MembershipPageBetaTesterSection(PageObject):
"""
Beta tester section of the Membership tab of the Instructor dashboard.
"""
url = None
batch_beta_tester_heading_selector = '#heading-batch-beta-testers'
batch_beta_tester_selector = '.batch-beta-testers'
def is_browser_on_page(self):
return self.q(css=self.batch_beta_tester_heading_selector).present
def fill_batch_beta_tester_addition_text_box(self, username):
"""
Fill in the form with the provided username and submit it.
"""
username_selector = "{} textarea".format(self.batch_beta_tester_selector)
enrollment_button = "{} .enrollment-button[data-action='add']".format(self.batch_beta_tester_selector)
# Fill the username after the username selector is visible.
self.wait_for_element_visibility(username_selector, 'username field is visible')
self.q(css=username_selector).fill(username)
# Verify enrollment button is present before clicking
self.wait_for_element_visibility(enrollment_button, 'Add beta testers button')
self.q(css=enrollment_button).click()
def get_notification_text(self):
"""
Check notification div is visible and have message.
"""
notification_selector = '{} .request-response'.format(self.batch_beta_tester_selector)
self.wait_for_element_visibility(notification_selector, 'Notification div is visible')
notification_header_text = self.q(css="{} h3".format(notification_selector)).text
notification_username = self.q(css="{} li".format(notification_selector)).text
return notification_header_text, notification_username
class SpecialExamsPageAllowanceSection(PageObject): class SpecialExamsPageAllowanceSection(PageObject):
""" """
Allowance section of the Instructor dashboard's Special Exams tab. Allowance section of the Instructor dashboard's Special Exams tab.
......
...@@ -213,6 +213,55 @@ class AutoEnrollmentWithCSVTest(BaseInstructorDashboardTest): ...@@ -213,6 +213,55 @@ class AutoEnrollmentWithCSVTest(BaseInstructorDashboardTest):
self.auto_enroll_section.a11y_audit.check_for_accessibility_errors() self.auto_enroll_section.a11y_audit.check_for_accessibility_errors()
class BatchBetaTestersTest(BaseInstructorDashboardTest):
"""
End-to-end tests for Batch beta testers functionality.
"""
def setUp(self):
super(BatchBetaTestersTest, self).setUp()
self.username = "test_{uuid}".format(uuid=self.unique_id[0:6])
self.email = "{user}@example.com".format(user=self.username)
AutoAuthPage(self.browser, username=self.username, email=self.email, is_active=False).visit()
self.course_fixture = CourseFixture(**self.course_info).install()
self.instructor_username = self.log_in_as_instructor()
instructor_dashboard_page = self.visit_instructor_dashboard()
self.batch_beta_tester_section = instructor_dashboard_page.select_membership().batch_beta_tester_addition()
self.inactive_user_message = 'These users could not be added as beta testers ' \
'because their accounts are not yet activated:'
def test_enroll_inactive_beta_tester(self):
"""
Scenario: On the Membership tab of the Instructor Dashboard, Batch Beta tester div is visible.
Given that I am on the Membership tab on the Instructor Dashboard
Then I enter the username and add it into beta testers.
Then I see the inactive user is not added in beta testers.
"""
self.batch_beta_tester_section.fill_batch_beta_tester_addition_text_box(self.username)
header_text, username = self.batch_beta_tester_section.get_notification_text()
self.assertIn(self.inactive_user_message, header_text[0])
self.assertEqual(self.username, username[0])
def test_enroll_active_and_inactive_beta_tester(self):
"""
Scenario: On the Membership tab of the Instructor Dashboard, Batch Beta tester div is visible.
Given that I am on the Membership tab on the Instructor Dashboard
Then I enter the active and inactive usernames and add it into beta testers.
Then I see the different messages related to active and inactive users.
"""
active_and_inactive_username = self.username + ',' + self.instructor_username[0]
self.batch_beta_tester_section.fill_batch_beta_tester_addition_text_box(active_and_inactive_username)
header_text, username = self.batch_beta_tester_section.get_notification_text()
# Verify that Inactive username and message.
self.assertIn(self.inactive_user_message, header_text[1])
self.assertEqual(self.username, username[1])
# Verify that active username and message.
self.assertIn('These users were successfully added as beta testers:', header_text[0])
self.assertEqual(self.instructor_username[0], username[0])
@attr(shard=10) @attr(shard=10)
class ProctoredExamsTest(BaseInstructorDashboardTest): class ProctoredExamsTest(BaseInstructorDashboardTest):
""" """
......
...@@ -196,20 +196,15 @@ def send_beta_role_email(action, user, email_params): ...@@ -196,20 +196,15 @@ def send_beta_role_email(action, user, email_params):
`user` is the User affected `user` is the User affected
`email_params` parameters used while parsing email templates (a `dict`). `email_params` parameters used while parsing email templates (a `dict`).
""" """
if action == 'add': if action in ('add', 'remove'):
email_params['message'] = 'add_beta_tester' email_params['message'] = '%s_beta_tester' % action
email_params['email_address'] = user.email email_params['email_address'] = user.email
email_params['full_name'] = user.profile.name email_params['full_name'] = user.profile.name
elif action == 'remove':
email_params['message'] = 'remove_beta_tester'
email_params['email_address'] = user.email
email_params['full_name'] = user.profile.name
else: else:
raise ValueError("Unexpected action received '{}' - expected 'add' or 'remove'".format(action)) raise ValueError("Unexpected action received '{}' - expected 'add' or 'remove'".format(action))
trying_to_add_inactive_user = not user.is_active and action == 'add'
send_mail_to_student(user.email, email_params, language=get_user_email_language(user)) if not trying_to_add_inactive_user:
send_mail_to_student(user.email, email_params, language=get_user_email_language(user))
def reset_student_attempts(course_id, student, module_state_key, requesting_user, delete_module=False): def reset_student_attempts(course_id, student, module_state_key, requesting_user, delete_module=False):
......
...@@ -1774,7 +1774,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1774,7 +1774,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": identifier, "identifier": identifier,
"error": False, "error": False,
"userDoesNotExist": False "userDoesNotExist": False,
"is_active": True
} }
] ]
} }
...@@ -1825,7 +1826,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1825,7 +1826,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": self.notenrolled_student.email, "identifier": self.notenrolled_student.email,
"error": False, "error": False,
"userDoesNotExist": False "userDoesNotExist": False,
"is_active": True
} }
] ]
} }
...@@ -1872,7 +1874,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1872,7 +1874,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": self.notenrolled_student.email, "identifier": self.notenrolled_student.email,
"error": False, "error": False,
"userDoesNotExist": False "userDoesNotExist": False,
"is_active": True
} }
] ]
} }
...@@ -1935,7 +1938,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1935,7 +1938,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": self.notregistered_email, "identifier": self.notregistered_email,
"error": True, "error": True,
"userDoesNotExist": True "userDoesNotExist": True,
"is_active": None
} }
] ]
} }
...@@ -1965,7 +1969,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1965,7 +1969,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": self.beta_tester.email, "identifier": self.beta_tester.email,
"error": False, "error": False,
"userDoesNotExist": False "userDoesNotExist": False,
"is_active": True
} }
] ]
} }
...@@ -1995,7 +2000,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll ...@@ -1995,7 +2000,8 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
{ {
"identifier": self.beta_tester.email, "identifier": self.beta_tester.email,
"error": False, "error": False,
"userDoesNotExist": False "userDoesNotExist": False,
"is_active": True
} }
] ]
} }
......
...@@ -760,6 +760,7 @@ def bulk_beta_modify_access(request, course_id): ...@@ -760,6 +760,7 @@ def bulk_beta_modify_access(request, course_id):
error = False error = False
user_does_not_exist = False user_does_not_exist = False
user = get_student_from_identifier(identifier) user = get_student_from_identifier(identifier)
user_active = user.is_active
if action == 'add': if action == 'add':
allow_access(course, user, rolename) allow_access(course, user, rolename)
...@@ -772,6 +773,7 @@ def bulk_beta_modify_access(request, course_id): ...@@ -772,6 +773,7 @@ def bulk_beta_modify_access(request, course_id):
except User.DoesNotExist: except User.DoesNotExist:
error = True error = True
user_does_not_exist = True user_does_not_exist = True
user_active = None
# catch and log any unexpected exceptions # catch and log any unexpected exceptions
# so that one error doesn't cause a 500. # so that one error doesn't cause a 500.
except Exception as exc: # pylint: disable=broad-except except Exception as exc: # pylint: disable=broad-except
...@@ -793,7 +795,8 @@ def bulk_beta_modify_access(request, course_id): ...@@ -793,7 +795,8 @@ def bulk_beta_modify_access(request, course_id):
results.append({ results.append({
'identifier': identifier, 'identifier': identifier,
'error': error, 'error': error,
'userDoesNotExist': user_does_not_exist 'userDoesNotExist': user_does_not_exist,
'is_active': user_active
}) })
response_payload = { response_payload = {
......
...@@ -461,16 +461,27 @@ such that the value can be defined later than this assignment (file load order). ...@@ -461,16 +461,27 @@ such that the value can be defined later than this assignment (file load order).
return displayResponse.$task_response.append($taskResSection); return displayResponse.$task_response.append($taskResSection);
}; };
if (successes.length && dataFromServer.action === 'add') { if (successes.length && dataFromServer.action === 'add') {
// Translators: A list of users appears after this sentence; var j, len1, inActiveUsers, activeUsers; // eslint-disable-line vars-on-top
renderList(gettext('These users were successfully added as beta testers:'), (function() { activeUsers = [];
var j, len1, results; inActiveUsers = [];
results = []; for (j = 0, len1 = successes.length; j < len1; j++) {
for (j = 0, len1 = successes.length; j < len1; j++) { sr = successes[j];
sr = successes[j]; if (sr.is_active) {
results.push(sr.identifier); activeUsers.push(sr.identifier);
} else {
inActiveUsers.push(sr.identifier);
} }
return results; }
}())); if (activeUsers.length) {
// Translators: A list of users appears after this sentence;
renderList(gettext('These users were successfully added as beta testers:'), activeUsers);
}
if (inActiveUsers.length) {
// Translators: A list of users appears after this sentence;
renderList(gettext(
'These users could not be added as beta testers because their accounts are not yet activated:'),
inActiveUsers);
}
} }
if (successes.length && dataFromServer.action === 'remove') { if (successes.length && dataFromServer.action === 'remove') {
// Translators: A list of users appears after this sentence; // Translators: A list of users appears after this sentence;
...@@ -524,7 +535,6 @@ such that the value can be defined later than this assignment (file load order). ...@@ -524,7 +535,6 @@ such that the value can be defined later than this assignment (file load order).
} }
return renderList(); return renderList();
}; };
return betaTesterBulkAddition; return betaTesterBulkAddition;
}()); }());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment