class TestAdminAndTeacherCourseSetup(unittest.TestCase): """CC1.10 - Admin and Teacher Course Setup.""" def setUp(self): """Pretest settings.""" self.ps = PastaSauce() self.desired_capabilities['name'] = self.id() self.teacher = Teacher( use_env_vars=True, pasta_user=self.ps, capabilities=self.desired_capabilities ) self.admin = Admin( use_env_vars=True, existing_driver=self.teacher.driver, pasta_user=self.ps, capabilities=self.desired_capabilities ) def tearDown(self): """Test destructor.""" self.ps.update_job( job_id=str(self.teacher.driver.session_id), **self.ps.test_updates ) try: self.admin.driver = None self.teacher.delete() except: pass # Case C7715 - 001 - Admin | Send course setup data from Sales Force @pytest.mark.skipif(str(7715) not in TESTS, reason='Excluded') def test_admin_send_course_setup_data_from_sales_force_7715(self): """Send course setup data from Sales Force. Steps: Go to tutor-staging.openstax.org and login as admin Click on the user menu Select the Admin option Click on Salesforce on the header Expected Result: """ self.ps.test_updates['name'] = 'cc1.10.001' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.001', '7715' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Admin' ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Salesforce') ) ).click() assert('salesforce' in self.admin.current_url()), 'not at salesforce' self.ps.test_updates['passed'] = True # Case C7716 - 002 - System | Course registration codes are emailed to the # teacher once the course is set up @pytest.mark.skipif(str(7716) not in TESTS, reason='Excluded') def test_system_registration_codes_are_emailed_to_teacher_7716(self): """Registration codes are emailed to teacher once the course is set up. Steps: Expected Result: """ self.ps.test_updates['name'] = 'cc1.10.002' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.002', '7716' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions raise NotImplementedError(inspect.currentframe().f_code.co_name) self.ps.test_updates['passed'] = True # Case C7717 - 003 - Teacher | Use a teacher registration code to access # their course @pytest.mark.skipif(str(7717) not in TESTS, reason='Excluded') def test_teacher_use_teacher_registration_code_to_access_course_7717(self): """Use a teacher registration code to access their course. Steps: Expected Result: """ self.ps.test_updates['name'] = 'cc1.10.003' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.003', '7717' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions raise NotImplementedError(inspect.currentframe().f_code.co_name) self.ps.test_updates['passed'] = True # Case C7718 - 004 - Teacher | Create course periods @pytest.mark.skipif(str(7718) not in TESTS, reason='Excluded') def test_teacher_create_course_periods_7718(self): """Create course periods. Steps: go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click "+ Add section" Enter a section name into the section Name text box Expected Result: New course section created """ self.ps.test_updates['name'] = 'cc1.10.004' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.004', '7718' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"add-period")]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys('test_period') self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Add"]' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="test_period"]') ) ) self.ps.test_updates['passed'] = True # Case C7719 - 005 - Teacher | View student enrollment code for # course period @pytest.mark.skipif(str(7719) not in TESTS, reason='Excluded') def test_teacher_view_student_enrollment_code_for_course_period_7719(self): """View the student enrollment code for a course period. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for selected section Click 'Get Student Enrollment Code' Expected Result: Student Enrollment code displayed along with instruction teacher can send to students on how to use enrollment code """ self.ps.test_updates['name'] = 'cc1.10.005' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.005', '7719' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//button[contains(@class,"show-enrollment-code")]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="enrollment-code"]') ) ) self.ps.test_updates['passed'] = True # Case C7720 - 006 - Teacher | Rename a course period @pytest.mark.skipif(str(7720) not in TESTS, reason='Excluded') def test_teacher_rename_a_course_period_7720(self): """Rename a course period. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for selected section Click 'Rename section' Enter new section name into the section Name text box Click on the 'Rename' button Expected Result: Section is renamed """ self.ps.test_updates['name'] = 'cc1.10.006' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.006', '7720' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() period_name = self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab"]') ) ).text self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//span[contains(@class,"rename-period")]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys('_EDIT') self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Rename"]' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '_EDIT"]') ) ) # then set it back to what it was before self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//span[contains(@class,"rename-period")]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys(Keys.BACK_SPACE * 5) self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Rename"]' ).click() self.ps.test_updates['passed'] = True # Case C7721 - 007 - Teacher | Archive an empty period @pytest.mark.skipif(str(7721) not in TESTS, reason='Excluded') def test_teacher_remove_an_empty_period_7721(self): """Remove an empty period. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for selected empty section Click 'Archive section' Click on the 'Archive' button Expected Result: Section is archived """ self.ps.test_updates['name'] = 'cc1.10.007' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.007', '7721' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions section_name = 'test_' + str(randint(0, 1000)) self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # create an empty section self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"add-period")]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys(section_name) self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Add"]' ).click() # archive the section just created self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + section_name + '"]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//a[contains(@class,"archive-period")]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@role="tooltip"]//button' + '//span[contains(text(),"Archive")]') ) ).click() self.teacher.sleep(2) archived = self.teacher.driver.find_elements( By.XPATH, '//li//a[@role="tab" and text()="' + section_name + '"]') assert(len(archived) == 0), ' not archived' self.ps.test_updates['passed'] = True # Case C7722 - 008 - Teacher | Archive a non-empty period @pytest.mark.skipif(str(7722) not in TESTS, reason='Excluded') def test_teacher_archive_a_nonempty_periods_7722(self): """Error message displayed if attempting to remove a non-empty period. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for selected non-empty section Click 'Archive section' Click Archive Expected Result: Section is archived """ self.ps.test_updates['name'] = 'cc1.10.008' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.008', '7722' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # name of period to archive (first tab) period_name = self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab"]') ) ).text # archive the section self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//a[contains(@class,"archive-period")]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@role="tooltip"]//button' + '//span[contains(text(),"Archive")]') ) ).click() self.teacher.sleep(2) archived = self.teacher.driver.find_elements( By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') assert(len(archived) == 0), ' not archived' # add the archived period back self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"view-archived-periods")]//button') ) ).click() periods = self.teacher.driver.find_elements( By.XPATH, '//div[@class="modal-content"]//tbody//tr' ) for period in periods: try: period.find_element( By.XPATH, ".//td[text()='" + period_name + "']") period.find_element( By.XPATH, ".//td//span[contains(@class,'restore-period')]//button" ).click() break except NoSuchElementException: if period == periods[-1]: raise Exception self.teacher.sleep(2) self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') ) ) self.ps.test_updates['passed'] = True # Case C58354 - 009 - Teacher | Unarchive a section @pytest.mark.skipif(str(58354) not in TESTS, reason='Excluded') def test_teacher_unarchive_a_section_58354(self): """Unarchive a section. Steps: go to tutor-qa.openstax.org log in as a teacher click on a Concept Coach book click on the user menu select course roster Click "View Archived Section" Click "Unarchive" for the desired section Expected Result: section is unarchived """ self.ps.test_updates['name'] = 'cc1.10.009' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.009', '58354' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # name of period to archive (first tab) period_name = self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab"]') ) ).text # archive the section self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//a[contains(@class,"archive-period")]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@role="tooltip"]//button' + '//span[contains(text(),"Archive")]') ) ).click() self.teacher.sleep(2) archived = self.teacher.driver.find_elements( By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') assert(len(archived) == 0), ' not archived' # add the archived period back self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"view-archived-periods")]//button') ) ).click() periods = self.teacher.driver.find_elements( By.XPATH, '//div[@class="modal-content"]//tbody//tr' ) for period in periods: try: period.find_element( By.XPATH, ".//td[text()='" + period_name + "']") period.find_element( By.XPATH, ".//td//span[contains(@class,'restore-period')]//button" ).click() break except NoSuchElementException: if period == periods[-1]: raise Exception self.teacher.sleep(2) self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]') ) ) self.ps.test_updates['passed'] = True # Case C7723 - 010 - Teacher | Rename the course @pytest.mark.skipif(str(7723) not in TESTS, reason='Excluded') def test_teacher_rename_the_course_7723(self): """Rename the course. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click 'Rename Course' Enter a new Course name into the Course Name text box Click on the 'Rename' button Expected Result: Course is renamed. """ self.ps.test_updates['name'] = 'cc1.10.010' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.010', '7723' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # rename section self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//span[@class="-rename-course-link"]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys("_EDIT") self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Rename"]' ).click() # check that the name was changed self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="course-settings-title"]' + '//span[contains(text(),"_EDIT")]') ) ) # change it back self.teacher.sleep(1) self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//span[@class="-rename-course-link"]//button') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="modal-content"]//input[@type="text"]') ) ).send_keys(Keys.BACK_SPACE * 5) self.teacher.driver.find_element( By.XPATH, '//div[@class="modal-content"]//button/span[text()="Rename"]' ).click() self.ps.test_updates['passed'] = True # Case C7724 - 011 - Teacher | Remove other teachers from the course @pytest.mark.skipif(str(7724) not in TESTS, reason='Excluded') def test_teacher_remove_other_teachers_from_the_course_7724(self): """Remove other teachers from the course. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on 'Remove' on the same row as selected teacher Click on the 'Remove' button Expected Result: Instructor is removed from the course """ self.ps.test_updates['name'] = 'cc1.10.011' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.011', '7724' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.driver.get( 'https://tutor-qa.openstax.org/admin/courses/8/edit') self.admin.page.wait_for_page_load() teacher_name = 'Trent' self.admin.driver.find_element( By.XPATH, '//a[contains(text(),"Teachers")]').click() self.admin.driver.find_element( By.ID, 'course_teacher').send_keys(teacher_name) self.admin.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name) ) ).click() self.admin.sleep(1) self.admin.driver.find_element( By.LINK_TEXT, 'Main Dashboard').click() self.admin.page.wait_for_page_load() self.admin.logout() # redo set-up, but make sure to go to course 8 self.teacher.login() self.teacher.driver.get('https://tutor-qa.openstax.org/courses/8') self.teacher.open_user_menu() self.teacher.wait.until( expect.element_to_be_clickable( (By.LINK_TEXT, 'Course Settings and Roster') ) ).click() self.teacher.page.wait_for_page_load() # delete teacher teachers_list = self.teacher.driver.find_elements( By.XPATH, '//div[@class="teachers-table"]//tbody//tr') for x in teachers_list: temp_first = x.find_element( By.XPATH, './td[1]' ).text if temp_first == teacher_name: x.find_element( By.XPATH, './/td//span[contains(text(),"Remove")]' ).click() self.teacher.sleep(1) self.teacher.driver.find_element( By.XPATH, '//div[@class="popover-content"]//button' ).click() break if x == teachers_list[-1]: print('added teacher was not found, and not deleted') raise Exception deleted_teacher = self.teacher.driver.find_elements( By.XPATH, '//td[contains(text(),"%s")]' % teacher_name) assert(len(deleted_teacher) == 0), 'teacher not deleted' self.ps.test_updates['passed'] = True # come back to this because adding teacher through admin first # Case C7725 - 012 - Teacher | Remove themself from the course @pytest.mark.skipif(str(7725) not in TESTS, reason='Excluded') def test_teacher_remove_themself_from_the_course_7725(self): """Remove themself from the course. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on 'Remove' on the same row as themselves Click on the 'Remove' button Expected Result: Teacher is removed from course and taken back to dashboard """ self.ps.test_updates['name'] = 'cc1.10.012' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.012', '7725' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.driver.get( 'https://tutor-qa.openstax.org/admin/courses/8/edit') self.admin.page.wait_for_page_load() teacher_name = 'Trent' self.admin.driver.find_element( By.XPATH, '//a[contains(text(),"Teachers")]').click() self.admin.driver.find_element( By.ID, 'course_teacher').send_keys(teacher_name) self.admin.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name) ) ).click() self.admin.sleep(1) self.admin.driver.find_element( By.LINK_TEXT, 'Main Dashboard').click() self.admin.page.wait_for_page_load() self.admin.logout() # redo set-up, but make sure to go to course 8 # login as the teacher just added to the course teacher2 = Teacher( username='******', password=os.getenv('TEACHER_PASSWORD'), existing_driver=self.teacher.driver ) teacher2.login() teacher2.driver.get('https://tutor-qa.openstax.org/courses/8') teacher2.open_user_menu() teacher2.wait.until( expect.element_to_be_clickable( (By.LINK_TEXT, 'Course Settings and Roster') ) ).click() teacher2.page.wait_for_page_load() # delete teacher teachers_list = teacher2.driver.find_elements( By.XPATH, '//div[@class="teachers-table"]//tbody//tr') for x in teachers_list: temp_first = x.find_element( By.XPATH, './td[1]' ).text if temp_first == teacher_name: x.find_element( By.XPATH, './/td//span[contains(text(),"Remove")]' ).click() teacher2.sleep(1) teacher2.driver.find_element( By.XPATH, '//div[@class="popover-content"]//button' ).click() break if x == teachers_list[-1]: print('added teacher was not found, and not deleted') raise Exception # after removing self from course taken to dashboard # or course if only 1 other course assert('/courses/8' not in teacher2.current_url()), \ 'teacher not deleted' teacher2.delete() self.ps.test_updates['passed'] = True # Case C7726 - 013 - Teacher | Transfer a student to another period @pytest.mark.skipif(str(7726) not in TESTS, reason='Excluded') def test_teacher_transfer_a_student_to_another_period_7726(self): """Transfer a student to another period. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for section selected student is currently enrolled in Click on 'Change Section' on the row of the selected student Click on section to move student to Expected Result: Student is moved to chosen section """ self.ps.test_updates['name'] = 'cc1.10.013' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.013', '7726' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # move student first_student = self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="period"]//tbody/tr[1]') ) ) student_name = first_student.find_element( By.XPATH, './/td[1]').text first_student.find_element( By.XPATH, './/td[@class="actions"]/a[@aria-describedby="change-period"]' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="popover-content"]//li[1]') ) ).click() # check that student was moved self.teacher.sleep(2) self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li[@tabindex="1"]//a[@role="tab"]') ) ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="period"]//tbody/tr' + '//td[text()="' + student_name + '"]') ) ) self.ps.test_updates['passed'] = True # Case C7727 - 014 - Teacher | Remove a student from a course @pytest.mark.skipif(str(7727) not in TESTS, reason='Excluded') def test_teacher_remove_a_student_from_a_course_7727(self): """Remove a student from a course. Steps: Go to Tutor Log in as a teacher Click on a Concept Coach book Click on the user menu Select course roster Click on tab for section selected student is currently enrolled in Click on 'Drop' on the row of the selected student Click on the 'Drop' button Expected Result: Student is dropped from the course """ self.ps.test_updates['name'] = 'cc1.10.014' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.014', '7727' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.teacher.login() self.teacher.driver.find_element( By.XPATH, '//a[contains(@href,"/cc-dashboard")]' ).click() self.teacher.page.wait_for_page_load() self.teacher.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Course Settings and Roster' ).click() # drop student first_student = self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@class="period"]//tbody/tr[1]') ) ) student_name = first_student.find_element( By.XPATH, './/td[1]').text first_student.find_element( By.XPATH, './/td[@class="actions"]/a[@aria-describedby="drop-student"]' ).click() self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[@id="drop-student"]//button') ) ).click() # check that student was removed self.teacher.sleep(2) self.teacher.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"dropped-students")]//tbody/tr' + '//td[text()="' + student_name + '"]') ) ) self.ps.test_updates['passed'] = True # Case C7728 - 015 - Admin | Impersonate a teacher @pytest.mark.skipif(str(7728) not in TESTS, reason='Excluded') def test_admin_impersonate_a_teacher_7728(self): """Impersonate a teacher. Steps: Go to Tutor Click on the 'Login' button Enter the admin user account in the username and password text boxes Click on the 'Sign in' button Click on the user's name in the top right corner to open drop down menu Click on the 'Admin' option of the drop down menu Click on 'Users' on the bar across the top [optional] Enter a teacher name into the search here text box Click on the 'Search' button Click on the 'Sign in as' button next to chosen teacher Expected Result: Signs in as chosen chosen teacher. Goes to chosen teacher's initial screen after login If multiple courses list of textbooks If one course straight to dashboard """ self.ps.test_updates['name'] = 'cc1.10.015' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.015', '7728' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.open_user_menu() self.admin.driver.find_element( By.LINK_TEXT, 'Admin' ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Users') ) ).click() self.admin.page.wait_for_page_load() self.admin.driver.find_element(By.ID, 'query').send_keys('teacher01') self.admin.driver.find_element( By.XPATH, '//input[@value="Search"]').click() self.admin.wait.until( expect.element_to_be_clickable( (By.XPATH, '//a[contains(text(),"Sign in as")]') ) ).click() self.admin.wait.until( expect.element_to_be_clickable( (By.XPATH, '//span[contains(text(),"Charles Morris")]') ) ) self.ps.test_updates['passed'] = True # Case C7729 - 016 - Admin | Change a course ecosystem @pytest.mark.skipif(str(7729) not in TESTS, reason='Excluded') def test_admin_change_a_course_ecosystem_7729(self): """Change a course ecosystem. Steps: Go to Tutor Click on the 'Login' button Enter the admin user account in the username and password text boxes Click on the 'Sign in' button Click on the 'Admin' button from the user menu Open the drop down menu by clicking 'Course Organization' Click the 'Courses' option Click the 'Edit' link for the desired course Click on the 'Course content' tab Select a different option in the 'Ecosystem' drop down menu Click the 'Submit' button Expected Result: Course ecosystem change is put on a queue """ self.ps.test_updates['name'] = 'cc1.10.016' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.016', '7729' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Admin' ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Course Organization') ) ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Courses') ) ).click() self.admin.page.wait_for_page_load() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Edit') ) ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Course content') ) ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.ID, 'ecosystem_id') ) ).send_keys('1' + Keys.ENTER) # self.admin.wait.until( # expect.visibility_of_element_located( # (By.XPATH, '//select[@id="ecosystem_id"]//option[1]') # ) # ).click() self.admin.driver.find_element( By.XPATH, '//div[@id="content"]//input[@type="submit"]' ).click() self.admin.sleep(1) self.admin.driver.find_element( By.XPATH, '//div[contains(@class,"alert-info")]' ) self.ps.test_updates['passed'] = True # Case C7730 - 017 - Admin | Change multiple course ecosystems in bulk @pytest.mark.skipif(str(7730) not in TESTS, reason='Excluded') def test_admin_change_multiple_course_ecosystems_in_bulk_7730(self): """Change multiple course ecosystems in bulk. Steps: Go to Tutor Click on the 'Login' button Enter the admin user account in the username and password text boxes Click on the 'Sign in' button Click on the 'Admin' button from the user menu Open the drop down menu by clicking 'Course Organization' Click the 'Courses' option Check the checkboxes next to selected courses Select an option in the 'Select an ecosystem' drop down menu Click the 'Set Ecosystem' button Expected Result: Course ecosystem change is put on a queue """ self.ps.test_updates['name'] = 'cc1.10.017' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.017', '7730' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions self.admin.login() self.admin.open_user_menu() self.teacher.driver.find_element( By.LINK_TEXT, 'Admin' ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Course Organization') ) ).click() self.admin.wait.until( expect.visibility_of_element_located( (By.LINK_TEXT, 'Courses') ) ).click() self.admin.page.wait_for_page_load() self.admin.wait.until( expect.visibility_of_element_located( (By.ID, 'courses_select_all') ) ).click() # click the checkmarks for two courses courses = self.admin.driver.find_elements( By.XPATH, '//input[@class="course_id_select"]') course_1 = courses[0] self.admin.driver.execute_script( 'return arguments[0].scrollIntoView();', course_1) self.admin.driver.execute_script('window.scrollBy(0, -120);') course_1.click() self.admin.sleep(0.5) course_2 = courses[1] self.admin.driver.execute_script( 'return arguments[0].scrollIntoView();', course_2) self.admin.driver.execute_script('window.scrollBy(0, -120);') course_2.click() self.admin.sleep(0.5) # scroll to bottom and set bulk ecosystems self.admin.driver.execute_script( "window.scrollTo(0, document.body.scrollHeight);") self.admin.wait.until( expect.visibility_of_element_located( (By.ID, 'ecosystem_id') ) ).send_keys('1' + Keys.ENTER) self.admin.wait.until( expect.visibility_of_element_located( (By.XPATH, '//div[contains(@class,"alert-info")]') ) ) self.ps.test_updates['passed'] = True # Case C7731 - 018 - Teacher | Receive a notice when students register @pytest.mark.skipif(str(7731) not in TESTS, reason='Excluded') def test_teacher_receive_a_notice_when_students_register_7731(self): """Receive a notice when students register. Steps: Expected Result: """ self.ps.test_updates['name'] = 'cc1.10.018' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = [ 'cc1', 'cc1.10', 'cc1.10.018', '7731' ] self.ps.test_updates['passed'] = False # Test steps and verification assertions raise NotImplementedError(inspect.currentframe().f_code.co_name) self.ps.test_updates['passed'] = True
def test_teacher_remove_the_last_instructor_from_the_course_8260(self): """Remove the last instructor from the course. Steps: Click on the user menu in the upper right corner of the page Click "Course Roster" Click "Remove" for an instructor under the Instructors section Click "Remove" on the box that pops up Expected Result: The instructor is removed from the Instructors list. """ self.ps.test_updates['name'] = 't1.42.003' \ + inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.003', '8260'] self.ps.test_updates['passed'] = False raise NotImplementedError(inspect.currentframe().f_code.co_name) self.teacher.logout() # add extra instructor through admin first admin = Admin( use_env_vars=True, existing_driver=self.teacher.driver, pasta_user=self.ps, capabilities=self.desired_capabilities ) admin.login() admin.get('https://tutor-qa.openstax.org/admin/courses/1/edit') admin.page.wait_for_page_load() teacher_name = 'Trent' admin.find( By.XPATH, '//a[contains(text(),"Teachers")]').click() admin.find( By.ID, 'course_teacher').send_keys(teacher_name) admin.wait.until( expect.visibility_of_element_located( (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name) ) ).click() admin.sleep(1) admin.find( By.LINK_TEXT, 'Main Dashboard').click() admin.page.wait_for_page_load() admin.logout() # redo set-up, but make sure to go to course 1 self.teacher.login() self.teacher.get('https://tutor-qa.openstax.org/courses/1') self.teacher.open_user_menu() self.teacher.wait.until( expect.element_to_be_clickable( (By.LINK_TEXT, 'Course Settings and Roster') ) ).click() self.teacher.page.wait_for_page_load() # delete teacher teachers_list = self.teacher.find_all( By.XPATH, '//div[@class="teachers-table"]//tbody//tr') for x in range(len(teachers_list)): temp_first = self.teacher.find( By.XPATH, '//div[@class="teachers-table"]//tbody//tr[' + str(x + 1) + ']/td' ).text if temp_first == teacher_name: self.teacher.find( By.XPATH, '//div[@class="teachers-table"]//tbody//tr[' + str(x + 1) + ']//td//span[contains(text(),"Remove")]' ).click() self.teacher.sleep(1) self.teacher.find( By.XPATH, '//div[@class="popover-content"]//button' ).click() break if x == len(teachers_list) - 1: print('added teacher was not found, and not deleted') raise Exception deleted_teacher = self.teacher.driver.find_elements( By.XPATH, '//td[contains(text(),"%s")]' % teacher_name) assert(len(deleted_teacher) == 0), 'teacher not deleted' self.ps.test_updates['passed'] = True
class TestTutorAdmin(unittest.TestCase): """Tutor | Teacher""" def setUp(self): """Pretest settings.""" self.ps = PastaSauce() self.desired_capabilities['name'] = self.id() if not LOCAL_RUN: self.admin = Admin( use_env_vars=True, pasta_user=self.ps, capabilities=self.desired_capabilities ) else: self.admin = Admin( use_env_vars=True ) def tearDown(self): """Test destructor.""" if not LOCAL_RUN: self.ps.update_job( job_id=str(self.teacher.driver.session_id), **self.ps.test_updates ) try: self.admin.delete() except: pass @pytest.mark.skipif(str(162255) not in TESTS, reason='Excluded') def test_admin_change_course_start_end_dates_162255(self): """ Log in as an Admin Go to the course management page Edit a course Change the term and course year Click Save ***Start and end dates should reflect the new term's timeframe*** Edit a course Change the Starts at date and Ends at date Click Save Expected Result: ***Start and end dates are changed*** https://trello.com/c/YuvX7DN0/25-admin-change-course-start-end-dates """ self.ps.test_updates['name'] = 'tutor_course_settings_admin_162255' + \ inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = ['tutor', 'course_settings', 'admin', '162255'] self.ps.test_updates['passed'] = False # go to courses admin page directly and log in URL = str(os.getenv('SERVER_URL')) + '/admin/courses' self.admin.login(url=URL) # search 'preview' in the search bar self.admin.find(By.CSS_SELECTOR, "#search-courses").send_keys('preview\n') self.admin.page.wait_for_page_load() pages = self.admin.find_all(By.CSS_SELECTOR, ".pagination>a") # go to very last page self.admin.scroll_to(pages[-2]) self.admin.sleep(1) pages[-2].click() # click on Edit button for very last course edit = self.admin.find_all(By.XPATH, ".//*[contains(text(),'Edit')]") self.admin.scroll_to(edit[-1]) edit[-1].click() # change year field by adding 1 yearfield = self.admin.find(By.CSS_SELECTOR, "#course_year") year = yearfield.get_attribute('value') newyear = str(int(year) + 1) yearfield.send_keys(len(year) * Keys.DELETE) yearfield.send_keys(newyear) # change start date and end date oldstartdatefield = self.admin.find(By.CSS_SELECTOR, "#course_starts_at") oldenddatefield = self.admin.find(By.CSS_SELECTOR, "#course_ends_at") # get start date and end date values oldstartdate = oldstartdatefield.get_attribute('value') oldenddate = oldenddatefield.get_attribute('value') change = datetime.timedelta(days=400) # converts start date and end date values into datetime objects and adds the change newstartdate = datetime.datetime.strptime( oldstartdate, '%Y-%m-%d %X %Z') + change # converts into a string format accepted by the form oldstartdatefield.send_keys( datetime.datetime.strftime( newstartdate, '%Y/%m/%d %X' )[:-3] ) # converts start date and end date values into datetime objects and adds change ( 400 days) newenddate = datetime.datetime.strptime( oldenddate, '%Y-%m-%d %X %Z') + change # converts into a string format accepted by teh form # newenddate = datetime.datetime.strftime(newenddate1, '%Y/%m/%d %X')[:-3] oldenddatefield.send_keys( datetime.datetime.strftime( newenddate, '%Y/%m/%d %X')[:-3] ) # saves changes self.admin.sleep(1) self.admin.find(By.CSS_SELECTOR, "#edit-save").click() self.admin.sleep(1) # updated start date and end date fields, get their values updatedstartdate = self.admin.find( By.CSS_SELECTOR, "#course_starts_at").get_attribute('value') updatedstartdatetime = datetime.datetime.strptime( updatedstartdate, '%Y-%m-%d %X %Z' ) updatedenddate = self.admin.find( By.CSS_SELECTOR, "#course_ends_at").get_attribute('value') updatedenddatetime = datetime.datetime.strptime( updatedenddate, '%Y-%m-%d %X %Z' ) # assert that the datetime objects I put into it are the ones in the updated field assert(newstartdate.isocalendar() == updatedstartdatetime.isocalendar()) assert(newenddate.isocalendar() == updatedenddatetime.isocalendar()) # change start date and end date to what it was yearfield = self.admin.find(By.CSS_SELECTOR, "#course_year") yearfield.send_keys(len(year) * Keys.DELETE) yearfield.send_keys(year) startdatefield = self.admin.find(By.CSS_SELECTOR, "#course_starts_at") startdatefield.send_keys(datetime.datetime.strftime( datetime.datetime.strptime(oldstartdate, '%Y-%m-%d %X %Z'), '%Y/%m/%d %X')[:-3] ) enddatefield = self.admin.find(By.CSS_SELECTOR, "#course_ends_at") enddatefield.send_keys(datetime.datetime.strftime( datetime.datetime.strptime(oldenddate, '%Y-%m-%d %X %Z'), '%Y/%m/%d %X')[:-3] ) self.admin.find(By.CSS_SELECTOR, "#edit-save").click() self.ps.test_updates['passed'] = True @pytest.mark.skipif(str(162256) not in TESTS, reason='Excluded') def test_notification_and_faulty_url_162256(self): """ Go to tutor qa Log in as admin Click "Admin" from the user menu Click "System Setting" Click "Notifications" Enter a new notification into the text box Click "Add" Log out of admin account Log in as a teacher ***An orange header with the notification pops up when you sign in*** Go to a fake url page to test if styled error page is displayed Expected result: ***a styled error page is displayed*** Corresponding test case: T2.18 001, 030 """ self.ps.test_updates['name'] = 'tutor_system_settings_admin_162256' + \ inspect.currentframe().f_code.co_name[4:] self.ps.test_updates['tags'] = ['tutor', 'system_settings', 'admin', '162256'] self.ps.test_updates['passed'] = False # go to admin instance self.admin.login(url=os.getenv('SERVER_URL') + '/admin') # go to system settings, then notifications, then set a notification self.admin.find(By.XPATH,".//*[contains(text(),'System Setting')]").click() self.admin.find(By.CSS_SELECTOR,"a[href*='notification']").click() self.admin.find(By.CSS_SELECTOR, "#message").send_keys('test_notification') self.admin.find(By.CSS_SELECTOR, ".btn.btn-default").click() # logout of admin self.admin.find(By.XPATH,".//*[contains(text(),'admin')]").click() self.admin.find(By.CSS_SELECTOR, 'a[href*="logout"]').click() # log into teacher account self.admin.login(username=os.getenv('TEACHER_USER'), password=os.getenv('TEACHER_PASSWORD')) self.admin.find(By.CSS_SELECTOR, '.my-courses-item-title>a').click() # if popup asking how you will be using Tutor shows up try: self.admin.find(By.XPATH, './/*[contains(text(),"I don’t know yet")]') except: pass # checks if notification is there self.admin.wait.until( expect.visibility_of_element_located(( By.XPATH, '//div[contains(@class,"notifications-bar")]' + '//span[text()="test_notification"]' )) ) self.admin.find( By.XPATH, '//div[contains(@class,"notifications-bar")]' + '//span[text()="test_notification"]' ) # log out of teacher self.admin.logout() # log into admin self.admin.login(url=os.getenv('SERVER_URL') + '/admin') self.admin.find(By.XPATH, '//a[text()="System Setting"]').click() self.admin.find(By.XPATH, '//a[text()="Notifications"]').click() # remove general notification self.admin.find(By.XPATH, '//a[text()="Remove"]').click() self.admin.driver.switch_to_alert().accept() # go to invalid website self.admin.get(os.getenv('SERVER_URL') + '/not_a_Real_page') # confirm styling of webpage self.admin.find(By.CSS_SELECTOR, '.invalid-page') self.ps.test_updates['passed'] = True