Merge pull request #11080 from edx/saleem-latif/SOL-1529

SOL-1529: Allow PMs to Invalidate Certificates
This commit is contained in:
Matt Drayer
2016-01-04 10:46:27 -05:00
19 changed files with 1399 additions and 29 deletions

View File

@@ -1006,6 +1006,16 @@ class CertificatesPage(PageObject):
)
self.wait_for_element_visibility('#add-exception', 'Add Exception button is visible')
def wait_for_certificate_invalidations_section(self): # pylint: disable=invalid-name
"""
Wait for certificate invalidations section to be rendered on page
"""
self.wait_for_element_visibility(
'div.certificate-invalidation-container',
'Certificate invalidations section is visible.'
)
self.wait_for_element_visibility('#invalidate-certificate', 'Invalidate Certificate button is visible')
def refresh(self):
"""
Refresh Certificates Page and wait for the page to load completely.
@@ -1064,6 +1074,42 @@ class CertificatesPage(PageObject):
"""
self.get_selector('#add-exception').click()
def add_certificate_invalidation(self, student, notes):
"""
Add certificate invalidation for 'student'.
"""
self.wait_for_element_visibility('#invalidate-certificate', 'Invalidate Certificate button is visible')
self.get_selector('#certificate-invalidation-user').fill(student)
self.get_selector('#certificate-invalidation-notes').fill(notes)
self.get_selector('#invalidate-certificate').click()
self.wait_for_ajax()
self.wait_for(
lambda: student in self.get_selector('div.invalidation-history table tr:last-child td').text,
description='Certificate invalidation added to list.'
)
def remove_first_certificate_invalidation(self):
"""
Remove certificate invalidation from the invalidation list.
"""
self.wait_for_element_visibility('#invalidate-certificate', 'Invalidate Certificate button is visible')
self.get_selector('div.invalidation-history table tr td .re-validate-certificate').first.click()
self.wait_for_ajax()
def fill_certificate_invalidation_user_name_field(self, student): # pylint: disable=invalid-name
"""
Fill username/email field with given text
"""
self.get_selector('#certificate-invalidation-user').fill(student)
def click_invalidate_certificate_button(self):
"""
Click 'Invalidate Certificate' button in 'certificates invalidations' section
"""
self.get_selector('#invalidate-certificate').click()
@property
def generate_certificates_button(self):
"""
@@ -1111,4 +1157,18 @@ class CertificatesPage(PageObject):
"""
Returns the Message (error/success) in "Certificate Exceptions" section.
"""
return self.get_selector('div.message')
return self.get_selector('.certificate-exception-container div.message')
@property
def last_certificate_invalidation(self):
"""
Returns last certificate invalidation from "Certificate Invalidations" section.
"""
return self.get_selector('div.certificate-invalidation-container table tr:last-child td')
@property
def certificate_invalidation_message(self): # pylint: disable=invalid-name
"""
Returns the message (error/success) in "Certificate Invalidation" section.
"""
return self.get_selector('.certificate-invalidation-container div.message')

View File

@@ -845,3 +845,202 @@ class CertificatesTest(BaseInstructorDashboardTest):
' below to send the certificate.',
self.certificates_section.message.text
)
@attr('shard_1')
class CertificateInvalidationTest(BaseInstructorDashboardTest):
"""
Tests for Certificates functionality on instructor dashboard.
"""
@classmethod
def setUpClass(cls):
super(CertificateInvalidationTest, cls).setUpClass()
# Create course fixture once each test run
CourseFixture(
org='test_org',
number='335535897951379478207964576572017930000',
run='test_run',
display_name='Test Course 335535897951379478207964576572017930000',
).install()
def setUp(self):
super(CertificateInvalidationTest, self).setUp()
# set same course number as we have in fixture json
self.course_info['number'] = "335535897951379478207964576572017930000"
# we have created a user with this id in fixture, and created a generated certificate for it.
self.student_id = "99"
self.student_name = "testcert"
self.student_email = "cert@example.com"
# Enroll above test user in the course
AutoAuthPage(
self.browser,
username=self.student_name,
email=self.student_email,
course_id=self.course_id,
).visit()
self.test_certificate_config = {
'id': 1,
'name': 'Certificate name',
'description': 'Certificate description',
'course_title': 'Course title override',
'signatories': [],
'version': 1,
'is_active': True
}
self.cert_fixture = CertificateConfigFixture(self.course_id, self.test_certificate_config)
self.cert_fixture.install()
self.user_name, self.user_id = self.log_in_as_instructor()
self.instructor_dashboard_page = self.visit_instructor_dashboard()
self.certificates_section = self.instructor_dashboard_page.select_certificates()
disable_animations(self.certificates_section)
def test_instructor_can_invalidate_certificate(self):
"""
Scenario: On the Certificates tab of the Instructor Dashboard, Instructor can add a certificate
invalidation to invalidation list.
Given that I am on the Certificates tab on the Instructor Dashboard
When I fill in student username and notes fields and click 'Add Exception' button
Then new certificate exception should be visible in certificate exceptions list
"""
notes = 'Test Notes'
# Add a student to certificate invalidation list
self.certificates_section.add_certificate_invalidation(self.student_name, notes)
self.assertIn(self.student_name, self.certificates_section.last_certificate_invalidation.text)
self.assertIn(notes, self.certificates_section.last_certificate_invalidation.text)
# Validate success message
self.assertIn(
"Certificate has been successfully invalidated for {user}.".format(user=self.student_name),
self.certificates_section.certificate_invalidation_message.text
)
# Verify that added invalidations are also synced with backend
# Revisit Page
self.certificates_section.refresh()
# wait for the certificate invalidations section to render
self.certificates_section.wait_for_certificate_invalidations_section()
# validate certificate invalidation is visible in certificate invalidation list
self.assertIn(self.student_name, self.certificates_section.last_certificate_invalidation.text)
self.assertIn(notes, self.certificates_section.last_certificate_invalidation.text)
def test_instructor_can_re_validate_certificate(self):
"""
Scenario: On the Certificates tab of the Instructor Dashboard, Instructor can re-validate certificate.
Given that I am on the certificates tab on the Instructor Dashboard
AND there is a certificate invalidation in certificate invalidation table
When I click "Remove from Invalidation Table" button
Then certificate is re-validated and removed from certificate invalidation table.
"""
notes = 'Test Notes'
# Add a student to certificate invalidation list
self.certificates_section.add_certificate_invalidation(self.student_name, notes)
self.assertIn(self.student_name, self.certificates_section.last_certificate_invalidation.text)
self.assertIn(notes, self.certificates_section.last_certificate_invalidation.text)
# Verify that added invalidations are also synced with backend
# Revisit Page
self.certificates_section.refresh()
# wait for the certificate invalidations section to render
self.certificates_section.wait_for_certificate_invalidations_section()
# click "Remove from Invalidation Table" button next to certificate invalidation
self.certificates_section.remove_first_certificate_invalidation()
# validate certificate invalidation is removed from the list
self.assertNotIn(self.student_name, self.certificates_section.last_certificate_invalidation.text)
self.assertNotIn(notes, self.certificates_section.last_certificate_invalidation.text)
self.assertIn(
"The certificate for this learner has been re-validated and the system is "
"re-running the grade for this learner.",
self.certificates_section.certificate_invalidation_message.text
)
def test_error_on_empty_user_name_or_email(self):
"""
Scenario: On the Certificates tab of the Instructor Dashboard, Instructor should see error message if he clicks
"Invalidate Certificate" button without entering student username or email.
Given that I am on the certificates tab on the Instructor Dashboard
When I click "Invalidate Certificate" button without entering student username/email.
Then I see following error message
"Student username/email field is required and can not be empty."
"Kindly fill in username/email and then press "Invalidate Certificate" button."
"""
# Click "Invalidate Certificate" with empty student username/email field
self.certificates_section.fill_certificate_invalidation_user_name_field("")
self.certificates_section.click_invalidate_certificate_button()
self.certificates_section.wait_for_ajax()
self.assertIn(
u'Student username/email field is required and can not be empty. '
u'Kindly fill in username/email and then press "Invalidate Certificate" button.',
self.certificates_section.certificate_invalidation_message.text
)
def test_error_on_invalid_user(self):
"""
Scenario: On the Certificates tab of the Instructor Dashboard, Instructor should see error message if
the student entered for certificate invalidation does not exist.
Given that I am on the certificates tab on the Instructor Dashboard
When I click "Invalidate Certificate"
AND the username entered does not exist in the system
Then I see following error message
"Student username/email field is required and can not be empty."
"Kindly fill in username/email and then press "Invalidate Certificate" button."
"""
invalid_user = "invalid_test_user"
# Click "Invalidate Certificate" with invalid student username/email
self.certificates_section.fill_certificate_invalidation_user_name_field(invalid_user)
self.certificates_section.click_invalidate_certificate_button()
self.certificates_section.wait_for_ajax()
self.assertIn(
u"{user} does not exist in the LMS. Please check your spelling and retry.".format(user=invalid_user),
self.certificates_section.certificate_invalidation_message.text
)
def test_user_not_enrolled_error(self):
"""
Scenario: On the Certificates tab of the Instructor Dashboard, Instructor should see error message if
the student entered for certificate invalidation is not enrolled in the course.
Given that I am on the certificates tab on the Instructor Dashboard
When I click "Invalidate Certificate"
AND the username entered is not enrolled in the current course
Then I see following error message
"{user} is not enrolled in this course. Please check your spelling and retry."
"""
new_user = 'test_user_{uuid}'.format(uuid=self.unique_id[6:12])
new_email = 'test_user_{uuid}@example.com'.format(uuid=self.unique_id[6:12])
# Create a new user who is not enrolled in the course
AutoAuthPage(self.browser, username=new_user, email=new_email).visit()
# Login as instructor and visit Certificate Section of Instructor Dashboard
self.user_name, self.user_id = self.log_in_as_instructor()
self.instructor_dashboard_page.visit()
self.certificates_section = self.instructor_dashboard_page.select_certificates()
# Click 'Invalidate Certificate' button with not enrolled student
self.certificates_section.wait_for_certificate_invalidations_section()
self.certificates_section.fill_certificate_invalidation_user_name_field(new_user)
self.certificates_section.click_invalidate_certificate_button()
self.certificates_section.wait_for_ajax()
self.assertIn(
u"{user} is not enrolled in this course. Please check your spelling and retry.".format(user=new_user),
self.certificates_section.certificate_invalidation_message.text
)