class CoursewareSearchTest(UniqueCourseTest): """ Test courseware search. """ USERNAME = '******' EMAIL = '*****@*****.**' STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" HTML_CONTENT = """ Someday I'll wish upon a star And wake up where the clouds are far Behind me. Where troubles melt like lemon drops Away above the chimney tops That's where you'll find me. """ SEARCH_STRING = "chimney" EDITED_CHAPTER_NAME = "Section 2 - edited" EDITED_SEARCH_STRING = "edited" TEST_INDEX_FILENAME = "test_root/index_file.dat" shard = 5 def setUp(self): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchTest, self).setUp() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.studio_course_outline = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) course_fix = CourseFixture(self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) course_fix.add_children( XBlockFixtureDesc('chapter', 'Section 1').add_children( XBlockFixtureDesc('sequential', 'Subsection 1'))).add_children( XBlockFixtureDesc('chapter', 'Section 2').add_children( XBlockFixtureDesc('sequential', 'Subsection 2'))).install() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() AutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_publish_content(self, section_index): """ Publish content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at( section_index).subsection_at(0) subsection.expand_subsection() unit = subsection.unit_at(0) unit.publish() def _studio_edit_chapter_name(self, section_index): """ Edit chapter name on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() section = self.studio_course_outline.section_at(section_index) section.change_name(self.EDITED_CHAPTER_NAME) def _studio_add_content(self, section_index): """ Add content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) # create a unit in course outline self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at( section_index).subsection_at(0) subsection.expand_subsection() subsection.add_unit() # got to unit and create an HTML component and save (not publish) unit_page = ContainerPage(self.browser, None) unit_page.wait_for_page() add_html_component(unit_page, 0) unit_page.wait_for_element_presence('.edit-button', 'Edit button is visible') click_css(unit_page, '.edit-button', 0, require_notification=False) unit_page.wait_for_element_visibility('.modal-editor', 'Modal editor is visible') type_in_codemirror(unit_page, 0, self.HTML_CONTENT) click_css(unit_page, '.action-save', 0) def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() self.studio_course_outline.start_reindex() self.studio_course_outline.wait_for_ajax() def _search_for_content(self, search_term): """ Login and search for specific content Arguments: search_term - term to be searched for Returns: (bool) True if search term is found in resulting content; False if not found """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.course_home_page.visit() course_search_results_page = self.course_home_page.search_for_term( search_term) if len(course_search_results_page.search_results.html) > 0: search_string = course_search_results_page.search_results.html[0] else: search_string = "" return search_term in search_string # TODO: TNL-6546: Remove usages of sidebar search def _search_for_content_in_sidebar(self, search_term, perform_auto_auth=True): """ Login and search for specific content in the legacy sidebar search Arguments: search_term - term to be searched for perform_auto_auth - if False, skip auto_auth call. Returns: (bool) True if search term is found in resulting content; False if not found """ if perform_auto_auth: self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page = CoursewareSearchPage( self.browser, self.course_id) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(search_term) return search_term in self.courseware_search_page.search_results.html[ 0] def test_search(self): """ Make sure that you can search for something. """ # Create content in studio without publishing. self._studio_add_content(0) # Do a search, there should be no results shown. self.assertFalse(self._search_for_content(self.SEARCH_STRING)) # Do a search in the legacy sidebar, there should be no results shown. self.assertFalse( self._search_for_content_in_sidebar(self.SEARCH_STRING, False)) # Publish in studio to trigger indexing. self._studio_publish_content(0) # Do the search again, this time we expect results. self.assertTrue(self._search_for_content(self.SEARCH_STRING)) # Do the search again in the legacy sidebar, this time we expect results. self.assertTrue( self._search_for_content_in_sidebar(self.SEARCH_STRING, False))
class CoursewareSearchTest(UniqueCourseTest): """ Test courseware search. """ USERNAME = '******' EMAIL = '*****@*****.**' STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" HTML_CONTENT = """ Someday I'll wish upon a star And wake up where the clouds are far Behind me. Where troubles melt like lemon drops Away above the chimney tops That's where you'll find me. """ SEARCH_STRING = "chimney" EDITED_CHAPTER_NAME = "Section 2 - edited" EDITED_SEARCH_STRING = "edited" TEST_INDEX_FILENAME = "test_root/index_file.dat" shard = 5 def setUp(self): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchTest, self).setUp() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.studio_course_outline = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Section 1').add_children( XBlockFixtureDesc('sequential', 'Subsection 1') ) ).add_children( XBlockFixtureDesc('chapter', 'Section 2').add_children( XBlockFixtureDesc('sequential', 'Subsection 2') ) ).install() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() AutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_publish_content(self, section_index): """ Publish content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at(section_index).subsection_at(0) subsection.expand_subsection() unit = subsection.unit_at(0) unit.publish() def _studio_edit_chapter_name(self, section_index): """ Edit chapter name on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() section = self.studio_course_outline.section_at(section_index) section.change_name(self.EDITED_CHAPTER_NAME) def _studio_add_content(self, section_index): """ Add content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) # create a unit in course outline self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at(section_index).subsection_at(0) subsection.expand_subsection() subsection.add_unit() # got to unit and create an HTML component and save (not publish) unit_page = ContainerPage(self.browser, None) unit_page.wait_for_page() add_html_component(unit_page, 0) unit_page.wait_for_element_presence('.edit-button', 'Edit button is visible') click_css(unit_page, '.edit-button', 0, require_notification=False) unit_page.wait_for_element_visibility('.modal-editor', 'Modal editor is visible') type_in_codemirror(unit_page, 0, self.HTML_CONTENT) click_css(unit_page, '.action-save', 0) def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() self.studio_course_outline.start_reindex() self.studio_course_outline.wait_for_ajax() def _search_for_content(self, search_term): """ Login and search for specific content Arguments: search_term - term to be searched for Returns: (bool) True if search term is found in resulting content; False if not found """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.course_home_page.visit() course_search_results_page = self.course_home_page.search_for_term(search_term) if len(course_search_results_page.search_results.html) > 0: search_string = course_search_results_page.search_results.html[0] else: search_string = "" return search_term in search_string # TODO: TNL-6546: Remove usages of sidebar search def _search_for_content_in_sidebar(self, search_term, perform_auto_auth=True): """ Login and search for specific content in the legacy sidebar search Arguments: search_term - term to be searched for perform_auto_auth - if False, skip auto_auth call. Returns: (bool) True if search term is found in resulting content; False if not found """ if perform_auto_auth: self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page = CoursewareSearchPage(self.browser, self.course_id) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(search_term) return search_term in self.courseware_search_page.search_results.html[0] def test_search(self): """ Make sure that you can search for something. """ # Create content in studio without publishing. self._studio_add_content(0) # Do a search, there should be no results shown. self.assertFalse(self._search_for_content(self.SEARCH_STRING)) # Do a search in the legacy sidebar, there should be no results shown. self.assertFalse(self._search_for_content_in_sidebar(self.SEARCH_STRING, False)) # Publish in studio to trigger indexing. self._studio_publish_content(0) # Do the search again, this time we expect results. self.assertTrue(self._search_for_content(self.SEARCH_STRING)) # Do the search again in the legacy sidebar, this time we expect results. self.assertTrue(self._search_for_content_in_sidebar(self.SEARCH_STRING, False))
class SplitTestCoursewareSearchTest(ContainerBase): """ Test courseware search on Split Test Module. """ USERNAME = '******' EMAIL = '*****@*****.**' TEST_INDEX_FILENAME = "test_root/index_file.dat" def setUp(self, is_staff=True): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(SplitTestCoursewareSearchTest, self).setUp(is_staff=is_staff) self.staff_user = self.user self.courseware_search_page = CoursewareSearchPage( self.browser, self.course_id) self.course_navigation_page = CourseNavPage(self.browser) self.course_outline = CourseOutlinePage(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self._create_group_configuration() self._studio_reindex() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() StudioAutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.course_outline.visit() self.course_outline.start_reindex() self.course_outline.wait_for_ajax() def _create_group_configuration(self): """ Create a group configuration for course """ # pylint: disable=protected-access self.course_fixture._update_xblock( self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, "Configuration A/B", "Content Group Partition.", [Group("0", "Group A"), Group("1", "Group B")]) ] } }) def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ course_fixture.add_advanced_settings({ u"advanced_modules": { "value": ["split_test"] }, }) course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'html', 'VISIBLE TO A', data='<html>VISIBLE TO A</html>', metadata={"group_access": { 0: [0] }}), XBlockFixtureDesc( 'html', 'VISIBLE TO B', data='<html>VISIBLE TO B</html>', metadata={"group_access": { 0: [1] }}))))) def test_page_existence(self): """ Make sure that the page is accessible. """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() def test_search_for_experiment_content_user_assigned_to_one_group(self): """ Test user can search for experiment content restricted to his group when assigned to just one experiment group """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term("VISIBLE TO") assert "1 result" in self.courseware_search_page.search_results.html[0]
class CoursewareSearchCohortTest(ContainerBase): """ Test courseware search. """ TEST_INDEX_FILENAME = "test_root/index_file.dat" def setUp(self, is_staff=True): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchCohortTest, self).setUp(is_staff=is_staff) self.staff_user = self.user self.studio_course_outline = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self.content_group_a = "Content Group A" self.content_group_b = "Content Group B" # Create a student who will be in "Cohort A" self.cohort_a_student_username = "******" + str( uuid.uuid4().hex)[:12] self.cohort_a_student_email = self.cohort_a_student_username + "@example.com" StudioAutoAuthPage(self.browser, username=self.cohort_a_student_username, email=self.cohort_a_student_email, no_login=True).visit() # Create a student who will be in "Cohort B" self.cohort_b_student_username = "******" + str( uuid.uuid4().hex)[:12] self.cohort_b_student_email = self.cohort_b_student_username + "@example.com" StudioAutoAuthPage(self.browser, username=self.cohort_b_student_username, email=self.cohort_b_student_email, no_login=True).visit() # Create a student who will end up in the default cohort group self.cohort_default_student_username = "******" self.cohort_default_student_email = "*****@*****.**" StudioAutoAuthPage(self.browser, username=self.cohort_default_student_username, email=self.cohort_default_student_email, no_login=True).visit() self.courseware_search_page = CoursewareSearchPage( self.browser, self.course_id) # Enable Cohorting and assign cohorts and content groups self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.enable_cohorting(self.course_fixture) self.create_content_groups() self.link_html_to_content_groups_and_publish() self.create_cohorts_and_assign_students() self._studio_reindex() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() StudioAutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.studio_course_outline.visit() self.studio_course_outline.start_reindex() self.studio_course_outline.wait_for_ajax() def _goto_staff_page(self): """ Open staff page with assertion """ self.courseware_search_page.visit() staff_page = StaffPage(self.browser, self.course_id) self.assertEqual(staff_page.staff_view_mode, 'Staff') return staff_page def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ self.group_a_html = 'GROUPACONTENT' self.group_b_html = 'GROUPBCONTENT' self.group_a_and_b_html = 'GROUPAANDBCONTENT' self.visible_to_all_html = 'VISIBLETOALLCONTENT' course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection'). add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', self.group_a_html, data='<html>GROUPACONTENT</html>'), XBlockFixtureDesc('html', self.group_b_html, data='<html>GROUPBCONTENT</html>'), XBlockFixtureDesc( 'html', self.group_a_and_b_html, data='<html>GROUPAANDBCONTENT</html>'), XBlockFixtureDesc( 'html', self.visible_to_all_html, data='<html>VISIBLETOALLCONTENT</html>'))))) def enable_cohorting(self, course_fixture): """ Enables cohorting for the current course. """ url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access data = json.dumps({'is_cohorted': True}) response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) self.assertTrue(response.ok, "Failed to enable cohorts") def create_content_groups(self): """ Creates two content groups in Studio Group Configurations Settings. """ group_configurations_page = GroupConfigurationsPage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) group_configurations_page.visit() group_configurations_page.create_first_content_group() config = group_configurations_page.content_groups[0] config.name = self.content_group_a config.save() group_configurations_page.add_content_group() config = group_configurations_page.content_groups[1] config.name = self.content_group_b config.save() def link_html_to_content_groups_and_publish(self): """ Updates 3 of the 4 existing html to limit their visibility by content group. Publishes the modified units. """ container_page = self.go_to_unit_page() def set_visibility(html_block_index, content_group, second_content_group=None): """ Set visibility on html blocks to specified groups. """ html_block = container_page.xblocks[html_block_index] html_block.edit_visibility() if second_content_group: ComponentVisibilityEditorView( self.browser, html_block.locator).select_option(second_content_group, save=False) ComponentVisibilityEditorView( self.browser, html_block.locator).select_option(content_group) set_visibility(1, self.content_group_a) set_visibility(2, self.content_group_b) set_visibility(3, self.content_group_a, self.content_group_b) set_visibility(4, 'All Students and Staff') # Does not work without this container_page.publish_action.click() def create_cohorts_and_assign_students(self): """ Adds 2 manual cohorts, linked to content groups, to the course. Each cohort is assigned one student. """ instructor_dashboard_page = InstructorDashboardPage( self.browser, self.course_id) instructor_dashboard_page.visit() cohort_management_page = instructor_dashboard_page.select_cohort_management( ) def add_cohort_with_student(cohort_name, content_group, student): """ Create cohort and assign student to it. """ cohort_management_page.add_cohort(cohort_name, content_group=content_group) cohort_management_page.add_students_to_selected_cohort([student]) add_cohort_with_student("Cohort A", self.content_group_a, self.cohort_a_student_username) add_cohort_with_student("Cohort B", self.content_group_b, self.cohort_b_student_username) cohort_management_page.wait_for_ajax() def test_page_existence(self): """ Make sure that the page is accessible. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() def test_cohorted_search_user_a_a_content(self): """ Test user can search content restricted to his cohort. """ self._auto_auth(self.cohort_a_student_username, self.cohort_a_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_b_a_content(self): """ Test user can not search content restricted to his cohort. """ self._auto_auth(self.cohort_b_student_username, self.cohort_b_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html not in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_default_ab_content(self): """ Test user not enrolled in any cohorts can't see any of restricted content. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html not in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_default_all_content(self): """ Test user can search public content if cohorts used on course. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_staff_all_content(self): """ Test staff user can search all public content if cohorts used on course. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Staff') self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_staff_masquerade_student_content(self): """ Test staff user can search just student public content if selected from preview menu. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Student') self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html not in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html not in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html not in self.courseware_search_page.search_results.html[ 0] def test_cohorted_search_user_staff_masquerade_cohort_content(self): """ Test staff user can search cohort and public content if selected from preview menu. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Student in ' + self.content_group_a) self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[ 0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html not in self.courseware_search_page.search_results.html[ 0]
class CoursewareSearchCohortTest(ContainerBase): """ Test courseware search. """ TEST_INDEX_FILENAME = "test_root/index_file.dat" def setUp(self, is_staff=True): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchCohortTest, self).setUp(is_staff=is_staff) self.staff_user = self.user self.course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.content_group_a = "Content Group A" self.content_group_b = "Content Group B" # Create a student who will be in "Cohort A" self.cohort_a_student_username = "******" + str(uuid.uuid4().hex)[:12] self.cohort_a_student_email = self.cohort_a_student_username + "@example.com" StudioAutoAuthPage( self.browser, username=self.cohort_a_student_username, email=self.cohort_a_student_email, no_login=True ).visit() # Create a student who will be in "Cohort B" self.cohort_b_student_username = "******" + str(uuid.uuid4().hex)[:12] self.cohort_b_student_email = self.cohort_b_student_username + "@example.com" StudioAutoAuthPage( self.browser, username=self.cohort_b_student_username, email=self.cohort_b_student_email, no_login=True ).visit() # Create a student who will end up in the default cohort group self.cohort_default_student_username = "******" self.cohort_default_student_email = "*****@*****.**" StudioAutoAuthPage( self.browser, username=self.cohort_default_student_username, email=self.cohort_default_student_email, no_login=True ).visit() self.courseware_search_page = CoursewareSearchPage(self.browser, self.course_id) # Enable Cohorting and assign cohorts and content groups self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.enable_cohorting(self.course_fixture) self.create_content_groups() self.link_html_to_content_groups_and_publish() self.create_cohorts_and_assign_students() self._studio_reindex() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() StudioAutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.course_outline.visit() self.course_outline.start_reindex() self.course_outline.wait_for_ajax() def _goto_staff_page(self): """ Open staff page with assertion """ self.courseware_search_page.visit() staff_page = StaffPage(self.browser, self.course_id) self.assertEqual(staff_page.staff_view_mode, 'Staff') return staff_page def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ self.group_a_html = 'GROUPACONTENT' self.group_b_html = 'GROUPBCONTENT' self.group_a_and_b_html = 'GROUPAANDBCONTENT' self.visible_to_all_html = 'VISIBLETOALLCONTENT' course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', self.group_a_html, data='<html>GROUPACONTENT</html>'), XBlockFixtureDesc('html', self.group_b_html, data='<html>GROUPBCONTENT</html>'), XBlockFixtureDesc('html', self.group_a_and_b_html, data='<html>GROUPAANDBCONTENT</html>'), XBlockFixtureDesc('html', self.visible_to_all_html, data='<html>VISIBLETOALLCONTENT</html>') ) ) ) ) def enable_cohorting(self, course_fixture): """ Enables cohorting for the current course. """ url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access data = json.dumps({'is_cohorted': True}) response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) self.assertTrue(response.ok, "Failed to enable cohorts") def create_content_groups(self): """ Creates two content groups in Studio Group Configurations Settings. """ group_configurations_page = GroupConfigurationsPage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) group_configurations_page.visit() group_configurations_page.create_first_content_group() config = group_configurations_page.content_groups[0] config.name = self.content_group_a config.save() group_configurations_page.add_content_group() config = group_configurations_page.content_groups[1] config.name = self.content_group_b config.save() def link_html_to_content_groups_and_publish(self): """ Updates 3 of the 4 existing html to limit their visibility by content group. Publishes the modified units. """ container_page = self.go_to_unit_page() def set_visibility(html_block_index, content_group, second_content_group=None): """ Set visibility on html blocks to specified groups. """ html_block = container_page.xblocks[html_block_index] html_block.edit_visibility() if second_content_group: ComponentVisibilityEditorView(self.browser, html_block.locator).select_option( second_content_group, save=False ) ComponentVisibilityEditorView(self.browser, html_block.locator).select_option(content_group) set_visibility(1, self.content_group_a) set_visibility(2, self.content_group_b) set_visibility(3, self.content_group_a, self.content_group_b) set_visibility(4, 'All Students and Staff') # Does not work without this container_page.publish_action.click() def create_cohorts_and_assign_students(self): """ Adds 2 manual cohorts, linked to content groups, to the course. Each cohort is assigned one student. """ instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id) instructor_dashboard_page.visit() cohort_management_page = instructor_dashboard_page.select_cohort_management() def add_cohort_with_student(cohort_name, content_group, student): """ Create cohort and assign student to it. """ cohort_management_page.add_cohort(cohort_name, content_group=content_group) cohort_management_page.add_students_to_selected_cohort([student]) add_cohort_with_student("Cohort A", self.content_group_a, self.cohort_a_student_username) add_cohort_with_student("Cohort B", self.content_group_b, self.cohort_b_student_username) cohort_management_page.wait_for_ajax() def test_page_existence(self): """ Make sure that the page is accessible. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() def test_cohorted_search_user_a_a_content(self): """ Test user can search content restricted to his cohort. """ self._auto_auth(self.cohort_a_student_username, self.cohort_a_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_b_a_content(self): """ Test user can not search content restricted to his cohort. """ self._auto_auth(self.cohort_b_student_username, self.cohort_b_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html not in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_default_ab_content(self): """ Test user not enrolled in any cohorts can't see any of restricted content. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html not in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_default_all_content(self): """ Test user can search public content if cohorts used on course. """ self._auto_auth(self.cohort_default_student_username, self.cohort_default_student_email, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_staff_all_content(self): """ Test staff user can search all public content if cohorts used on course. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Staff') self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_staff_masquerade_student_content(self): """ Test staff user can search just student public content if selected from preview menu. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Student') self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html not in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html not in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html not in self.courseware_search_page.search_results.html[0] def test_cohorted_search_user_staff_masquerade_cohort_content(self): """ Test staff user can search cohort and public content if selected from preview menu. """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], False) self._goto_staff_page().set_staff_view_mode('Student in ' + self.content_group_a) self.courseware_search_page.search_for_term(self.visible_to_all_html) assert self.visible_to_all_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_and_b_html) assert self.group_a_and_b_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_a_html) assert self.group_a_html in self.courseware_search_page.search_results.html[0] self.courseware_search_page.clear_search() self.courseware_search_page.search_for_term(self.group_b_html) assert self.group_b_html not in self.courseware_search_page.search_results.html[0]
class CoursewareSearchTest(UniqueCourseTest): """ Test courseware search. """ USERNAME = "******" EMAIL = "*****@*****.**" STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" HTML_CONTENT = """ Someday I'll wish upon a star And wake up where the clouds are far Behind me. Where troubles melt like lemon drops Away above the chimney tops That's where you'll find me. """ SEARCH_STRING = "chimney" EDITED_CHAPTER_NAME = "Section 2 - edited" EDITED_SEARCH_STRING = "edited" TEST_INDEX_FILENAME = "test_root/index_file.dat" def setUp(self): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchTest, self).setUp() self.courseware_search_page = CoursewareSearchPage(self.browser, self.course_id) self.course_outline = CourseOutlinePage( self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"] ) course_fix = CourseFixture( self.course_info["org"], self.course_info["number"], self.course_info["run"], self.course_info["display_name"], ) course_fix.add_children( XBlockFixtureDesc("chapter", "Section 1").add_children(XBlockFixtureDesc("sequential", "Subsection 1")) ).add_children( XBlockFixtureDesc("chapter", "Section 2").add_children(XBlockFixtureDesc("sequential", "Subsection 2")) ).install() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() AutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_publish_content(self, section_index): """ Publish content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.course_outline.visit() subsection = self.course_outline.section_at(section_index).subsection_at(0) subsection.expand_subsection() unit = subsection.unit_at(0) unit.publish() def _studio_edit_chapter_name(self, section_index): """ Edit chapter name on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.course_outline.visit() section = self.course_outline.section_at(section_index) section.change_name(self.EDITED_CHAPTER_NAME) def _studio_add_content(self, section_index): """ Add content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) # create a unit in course outline self.course_outline.visit() subsection = self.course_outline.section_at(section_index).subsection_at(0) subsection.expand_subsection() subsection.add_unit() # got to unit and create an HTML component and save (not publish) unit_page = ContainerPage(self.browser, None) unit_page.wait_for_page() add_html_component(unit_page, 0) unit_page.wait_for_element_presence(".edit-button", "Edit button is visible") click_css(unit_page, ".edit-button", 0, require_notification=False) unit_page.wait_for_element_visibility(".modal-editor", "Modal editor is visible") type_in_codemirror(unit_page, 0, self.HTML_CONTENT) click_css(unit_page, ".action-save", 0) def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.course_outline.visit() self.course_outline.start_reindex() self.course_outline.wait_for_ajax() def _search_for_content(self, search_term): """ Login and search for specific content Arguments: search_term - term to be searched for Returns: (bool) True if search term is found in resulting content; False if not found """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term(search_term) return search_term in self.courseware_search_page.search_results.html[0] def test_page_existence(self): """ Make sure that the page is accessible. """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() def test_search(self): """ Make sure that you can search for something. """ # Create content in studio without publishing. self._studio_add_content(0) # Do a search, there should be no results shown. self.assertFalse(self._search_for_content(self.SEARCH_STRING)) # Publish in studio to trigger indexing. self._studio_publish_content(0) # Do the search again, this time we expect results. self.assertTrue(self._search_for_content(self.SEARCH_STRING)) def test_reindex(self): """ Make sure new content gets reindexed on button press. """ # Create content in studio without publishing. self._studio_add_content(1) # Do a search, there should be no results shown. self.assertFalse(self._search_for_content(self.EDITED_SEARCH_STRING)) # Publish in studio to trigger indexing, and edit chapter name afterwards. self._studio_publish_content(1) # Do a ReIndex from studio to ensure that our stuff is updated before the next stage of the test self._studio_reindex() # Search after publish, there should still be no results shown. self.assertFalse(self._search_for_content(self.EDITED_SEARCH_STRING)) self._studio_edit_chapter_name(1) # Do a ReIndex from studio to ensure that our stuff is updated before the next stage of the test self._studio_reindex() # Do the search again, this time we expect results. self.assertTrue(self._search_for_content(self.EDITED_SEARCH_STRING))
class SplitTestCoursewareSearchTest(ContainerBase): """ Test courseware search on Split Test Module. """ USERNAME = '******' EMAIL = '*****@*****.**' TEST_INDEX_FILENAME = "test_root/index_file.dat" def setUp(self, is_staff=True): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(SplitTestCoursewareSearchTest, self).setUp(is_staff=is_staff) self.staff_user = self.user self.courseware_search_page = CoursewareSearchPage(self.browser, self.course_id) self.course_navigation_page = CourseNavPage(self.browser) self.course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self._create_group_configuration() self._studio_reindex() def _auto_auth(self, username, email, staff): """ Logout and login with given credentials. """ LogoutPage(self.browser).visit() StudioAutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() def _studio_reindex(self): """ Reindex course content on studio course page """ self._auto_auth(self.staff_user["username"], self.staff_user["email"], True) self.course_outline.visit() self.course_outline.start_reindex() self.course_outline.wait_for_ajax() def _create_group_configuration(self): """ Create a group configuration for course """ # pylint: disable=protected-access self.course_fixture._update_xblock(self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, "Configuration A/B", "Content Group Partition.", [Group("0", "Group A"), Group("1", "Group B")] ) ] } }) def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ course_fixture.add_advanced_settings({ u"advanced_modules": {"value": ["split_test"]}, }) course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'html', 'VISIBLE TO A', data='<html>VISIBLE TO A</html>', metadata={"group_access": {0: [0]}} ), XBlockFixtureDesc( 'html', 'VISIBLE TO B', data='<html>VISIBLE TO B</html>', metadata={"group_access": {0: [1]}} ) ) ) ) ) def test_page_existence(self): """ Make sure that the page is accessible. """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() def test_search_for_experiment_content_user_assigned_to_one_group(self): """ Test user can search for experiment content restricted to his group when assigned to just one experiment group """ self._auto_auth(self.USERNAME, self.EMAIL, False) self.courseware_search_page.visit() self.courseware_search_page.search_for_term("VISIBLE TO") assert "1 result" in self.courseware_search_page.search_results.html[0]