class CoursewareMultipleVerticalsTest(UniqueCourseTest, EventsTestMixin): """ Test courseware with multiple verticals """ USERNAME = "******" EMAIL = "*****@*****.**" def setUp(self): super(CoursewareMultipleVerticalsTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_outline = CourseOutlinePage(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) # Install a course with sections/problems, tabs, updates, and handouts 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', 'Test Section 1').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection 1,1').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 1', data='<problem>problem 1 dummy body</problem>'), XBlockFixtureDesc( 'html', 'html 1', data="<html>html 1 dummy body</html>"), XBlockFixtureDesc( 'problem', 'Test Problem 2', data="<problem>problem 2 dummy body</problem>"), XBlockFixtureDesc( 'html', 'html 2', data="<html>html 2 dummy body</html>"), ), XBlockFixtureDesc( 'sequential', 'Test Subsection 1,2').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 3', data='<problem>problem 3 dummy body</problem>'), ), XBlockFixtureDesc( 'sequential', 'Test HIDDEN Subsection', metadata={ 'visible_to_staff_only': True }).add_children( XBlockFixtureDesc( 'problem', 'Test HIDDEN Problem', data='<problem>hidden problem</problem>'), ), ), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection 2,1').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 4', data='<problem>problem 4 dummy body</problem>'), ), ), XBlockFixtureDesc( 'chapter', 'Test HIDDEN Section', metadata={ 'visible_to_staff_only': True }).add_children( XBlockFixtureDesc('sequential', 'Test HIDDEN Subsection'), ), ).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit() self.courseware_page.visit() self.course_nav = CourseNavPage(self.browser) def test_navigation_buttons(self): # start in first section self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 0, next_enabled=True, prev_enabled=False) # next takes us to next tab in sequential self.courseware_page.click_next_button_on_top() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 1, next_enabled=True, prev_enabled=True) # go to last sequential position self.courseware_page.go_to_sequential_position(4) self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 3, next_enabled=True, prev_enabled=True) # next takes us to next sequential self.courseware_page.click_next_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,2', 0, next_enabled=True, prev_enabled=True) # next takes us to next chapter self.courseware_page.click_next_button_on_top() self.assert_navigation_state('Test Section 2', 'Test Subsection 2,1', 0, next_enabled=False, prev_enabled=True) # previous takes us to previous chapter self.courseware_page.click_previous_button_on_top() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,2', 0, next_enabled=True, prev_enabled=True) # previous takes us to last tab in previous sequential self.courseware_page.click_previous_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 3, next_enabled=True, prev_enabled=True) # previous takes us to previous tab in sequential self.courseware_page.click_previous_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 2, next_enabled=True, prev_enabled=True) # test UI events emitted by navigation filter_sequence_ui_event = lambda event: event.get( 'name', '').startswith('edx.ui.lms.sequence.') sequence_ui_events = self.wait_for_events( event_filter=filter_sequence_ui_event, timeout=2) legacy_events = [ ev for ev in sequence_ui_events if ev['event_type'] in {'seq_next', 'seq_prev', 'seq_goto'} ] nonlegacy_events = [ ev for ev in sequence_ui_events if ev not in legacy_events ] self.assertTrue( all('old' in json.loads(ev['event']) for ev in legacy_events)) self.assertTrue( all('new' in json.loads(ev['event']) for ev in legacy_events)) self.assertFalse( any('old' in json.loads(ev['event']) for ev in nonlegacy_events)) self.assertFalse( any('new' in json.loads(ev['event']) for ev in nonlegacy_events)) self.assert_events_match([ { 'event_type': 'seq_next', 'event': { 'old': 1, 'new': 2, 'current_tab': 1, 'tab_count': 4, 'widget_placement': 'top', } }, { 'event_type': 'seq_goto', 'event': { 'old': 2, 'new': 4, 'current_tab': 2, 'target_tab': 4, 'tab_count': 4, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.next_selected', 'event': { 'current_tab': 4, 'tab_count': 4, 'widget_placement': 'bottom', } }, { 'event_type': 'edx.ui.lms.sequence.next_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.previous_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.previous_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'bottom', } }, { 'event_type': 'seq_prev', 'event': { 'old': 4, 'new': 3, 'current_tab': 4, 'tab_count': 4, 'widget_placement': 'bottom', } }, ], sequence_ui_events) def test_outline_selected_events(self): self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,2') self.course_nav.go_to_section('Test Section 2', 'Test Subsection 2,1') # test UI events emitted by navigating via the course outline filter_selected_events = lambda event: event.get( 'name', '') == 'edx.ui.lms.outline.selected' selected_events = self.wait_for_events( event_filter=filter_selected_events, timeout=2) # note: target_url is tested in unit tests, as the url changes here with every test (it includes GUIDs). self.assert_events_match([ { 'event_type': 'edx.ui.lms.outline.selected', 'name': 'edx.ui.lms.outline.selected', 'event': { 'target_name': 'Test Subsection 1,2 ', 'widget_placement': 'accordion', } }, { 'event_type': 'edx.ui.lms.outline.selected', 'name': 'edx.ui.lms.outline.selected', 'event': { 'target_name': 'Test Subsection 2,1 ', 'widget_placement': 'accordion', } }, ], selected_events) def test_link_clicked_events(self): """ Given that I am a user in the courseware When I navigate via the left-hand nav Then a link clicked event is logged """ self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,2') self.course_nav.go_to_section('Test Section 2', 'Test Subsection 2,1') filter_link_clicked = lambda event: event.get( 'name', '') == 'edx.ui.lms.link_clicked' link_clicked_events = self.wait_for_events( event_filter=filter_link_clicked, timeout=2) self.assertEqual(len(link_clicked_events), 2) def assert_navigation_state(self, section_title, subsection_title, subsection_position, next_enabled, prev_enabled): """ Verifies that the navigation state is as expected. """ self.assertTrue( self.course_nav.is_on_section(section_title, subsection_title)) self.assertEquals(self.courseware_page.sequential_position, subsection_position) self.assertEquals(self.courseware_page.is_next_button_enabled, next_enabled) self.assertEquals(self.courseware_page.is_previous_button_enabled, prev_enabled) def test_tab_position(self): # test that using the position in the url direct to correct tab in courseware self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,1') subsection_url = self.course_nav.active_subsection_url url_part_list = subsection_url.split('/') self.assertEqual(len(url_part_list), 9) course_id = url_part_list[4] chapter_id = url_part_list[-3] subsection_id = url_part_list[-2] problem1_page = CoursewareSequentialTabPage(self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=1).visit() self.assertIn('problem 1 dummy body', problem1_page.get_selected_tab_content()) html1_page = CoursewareSequentialTabPage(self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=2).visit() self.assertIn('html 1 dummy body', html1_page.get_selected_tab_content()) problem2_page = CoursewareSequentialTabPage(self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=3).visit() self.assertIn('problem 2 dummy body', problem2_page.get_selected_tab_content()) html2_page = CoursewareSequentialTabPage(self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=4).visit() self.assertIn('html 2 dummy body', html2_page.get_selected_tab_content()) @attr('a11y') def test_courseware_a11y(self): """ Run accessibility audit for the problem type. """ self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,1') # Set the scope to the sequence navigation self.courseware_page.a11y_audit.config.set_scope( include=['div.sequence-nav']) self.courseware_page.a11y_audit.check_for_accessibility_errors()
class CoursewareMultipleVerticalsTest(UniqueCourseTest, EventsTestMixin): """ Test courseware with multiple verticals """ USERNAME = "******" EMAIL = "*****@*****.**" def setUp(self): super(CoursewareMultipleVerticalsTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) # Install a course with sections/problems, tabs, updates, and handouts 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', 'Test Section 1').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 1,1').add_children( XBlockFixtureDesc('problem', 'Test Problem 1', data='<problem>problem 1 dummy body</problem>'), XBlockFixtureDesc('html', 'html 1', data="<html>html 1 dummy body</html>"), XBlockFixtureDesc('problem', 'Test Problem 2', data="<problem>problem 2 dummy body</problem>"), XBlockFixtureDesc('html', 'html 2', data="<html>html 2 dummy body</html>"), ), XBlockFixtureDesc('sequential', 'Test Subsection 1,2').add_children( XBlockFixtureDesc('problem', 'Test Problem 3', data='<problem>problem 3 dummy body</problem>'), ), XBlockFixtureDesc( 'sequential', 'Test HIDDEN Subsection', metadata={'visible_to_staff_only': True} ).add_children( XBlockFixtureDesc('problem', 'Test HIDDEN Problem', data='<problem>hidden problem</problem>'), ), ), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 2,1').add_children( XBlockFixtureDesc('problem', 'Test Problem 4', data='<problem>problem 4 dummy body</problem>'), ), ), XBlockFixtureDesc('chapter', 'Test HIDDEN Section', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('sequential', 'Test HIDDEN Subsection'), ), ).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit() self.courseware_page.visit() self.course_nav = CourseNavPage(self.browser) def test_navigation_buttons(self): # start in first section self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 0, next_enabled=True, prev_enabled=False) # next takes us to next tab in sequential self.courseware_page.click_next_button_on_top() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 1, next_enabled=True, prev_enabled=True) # go to last sequential position self.courseware_page.go_to_sequential_position(4) self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 3, next_enabled=True, prev_enabled=True) # next takes us to next sequential self.courseware_page.click_next_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,2', 0, next_enabled=True, prev_enabled=True) # next takes us to next chapter self.courseware_page.click_next_button_on_top() self.assert_navigation_state('Test Section 2', 'Test Subsection 2,1', 0, next_enabled=False, prev_enabled=True) # previous takes us to previous chapter self.courseware_page.click_previous_button_on_top() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,2', 0, next_enabled=True, prev_enabled=True) # previous takes us to last tab in previous sequential self.courseware_page.click_previous_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 3, next_enabled=True, prev_enabled=True) # previous takes us to previous tab in sequential self.courseware_page.click_previous_button_on_bottom() self.assert_navigation_state('Test Section 1', 'Test Subsection 1,1', 2, next_enabled=True, prev_enabled=True) # test UI events emitted by navigation filter_sequence_ui_event = lambda event: event.get('name', '').startswith('edx.ui.lms.sequence.') sequence_ui_events = self.wait_for_events(event_filter=filter_sequence_ui_event, timeout=2) legacy_events = [ev for ev in sequence_ui_events if ev['event_type'] in {'seq_next', 'seq_prev', 'seq_goto'}] nonlegacy_events = [ev for ev in sequence_ui_events if ev not in legacy_events] self.assertTrue(all('old' in json.loads(ev['event']) for ev in legacy_events)) self.assertTrue(all('new' in json.loads(ev['event']) for ev in legacy_events)) self.assertFalse(any('old' in json.loads(ev['event']) for ev in nonlegacy_events)) self.assertFalse(any('new' in json.loads(ev['event']) for ev in nonlegacy_events)) self.assert_events_match( [ { 'event_type': 'seq_next', 'event': { 'old': 1, 'new': 2, 'current_tab': 1, 'tab_count': 4, 'widget_placement': 'top', } }, { 'event_type': 'seq_goto', 'event': { 'old': 2, 'new': 4, 'current_tab': 2, 'target_tab': 4, 'tab_count': 4, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.next_selected', 'event': { 'current_tab': 4, 'tab_count': 4, 'widget_placement': 'bottom', } }, { 'event_type': 'edx.ui.lms.sequence.next_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.previous_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'top', } }, { 'event_type': 'edx.ui.lms.sequence.previous_selected', 'event': { 'current_tab': 1, 'tab_count': 1, 'widget_placement': 'bottom', } }, { 'event_type': 'seq_prev', 'event': { 'old': 4, 'new': 3, 'current_tab': 4, 'tab_count': 4, 'widget_placement': 'bottom', } }, ], sequence_ui_events ) def test_outline_selected_events(self): self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,2') self.course_nav.go_to_section('Test Section 2', 'Test Subsection 2,1') # test UI events emitted by navigating via the course outline filter_selected_events = lambda event: event.get('name', '') == 'edx.ui.lms.outline.selected' selected_events = self.wait_for_events(event_filter=filter_selected_events, timeout=2) # note: target_url is tested in unit tests, as the url changes here with every test (it includes GUIDs). self.assert_events_match( [ { 'event_type': 'edx.ui.lms.outline.selected', 'name': 'edx.ui.lms.outline.selected', 'event': { 'target_name': 'Test Subsection 1,2 ', 'widget_placement': 'accordion', } }, { 'event_type': 'edx.ui.lms.outline.selected', 'name': 'edx.ui.lms.outline.selected', 'event': { 'target_name': 'Test Subsection 2,1 ', 'widget_placement': 'accordion', } }, ], selected_events ) def test_link_clicked_events(self): """ Given that I am a user in the courseware When I navigate via the left-hand nav Then a link clicked event is logged """ self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,2') self.course_nav.go_to_section('Test Section 2', 'Test Subsection 2,1') filter_link_clicked = lambda event: event.get('name', '') == 'edx.ui.lms.link_clicked' link_clicked_events = self.wait_for_events(event_filter=filter_link_clicked, timeout=2) self.assertEqual(len(link_clicked_events), 2) def assert_navigation_state( self, section_title, subsection_title, subsection_position, next_enabled, prev_enabled ): """ Verifies that the navigation state is as expected. """ self.assertTrue(self.course_nav.is_on_section(section_title, subsection_title)) self.assertEquals(self.courseware_page.sequential_position, subsection_position) self.assertEquals(self.courseware_page.is_next_button_enabled, next_enabled) self.assertEquals(self.courseware_page.is_previous_button_enabled, prev_enabled) def test_tab_position(self): # test that using the position in the url direct to correct tab in courseware self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,1') subsection_url = self.course_nav.active_subsection_url url_part_list = subsection_url.split('/') self.assertEqual(len(url_part_list), 9) course_id = url_part_list[4] chapter_id = url_part_list[-3] subsection_id = url_part_list[-2] problem1_page = CoursewareSequentialTabPage( self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=1 ).visit() self.assertIn('problem 1 dummy body', problem1_page.get_selected_tab_content()) html1_page = CoursewareSequentialTabPage( self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=2 ).visit() self.assertIn('html 1 dummy body', html1_page.get_selected_tab_content()) problem2_page = CoursewareSequentialTabPage( self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=3 ).visit() self.assertIn('problem 2 dummy body', problem2_page.get_selected_tab_content()) html2_page = CoursewareSequentialTabPage( self.browser, course_id=course_id, chapter=chapter_id, subsection=subsection_id, position=4 ).visit() self.assertIn('html 2 dummy body', html2_page.get_selected_tab_content()) @attr('a11y') def test_courseware_a11y(self): """ Run accessibility audit for the problem type. """ self.course_nav.go_to_section('Test Section 1', 'Test Subsection 1,1') # Set the scope to the sequence navigation self.courseware_page.a11y_audit.config.set_scope( include=['div.sequence-nav']) self.courseware_page.a11y_audit.check_for_accessibility_errors()