From d9fe111c5bdacfb0d1e3894f81d84e41b9f24d82 Mon Sep 17 00:00:00 2001 From: Muhammad Ammar Date: Wed, 28 May 2014 10:33:12 +0000 Subject: [PATCH] Bok-Choy Video Tests Batch9 --- .../test/acceptance/pages/lms/course_nav.py | 11 + .../test/acceptance/pages/lms/video/video.py | 61 +++++- .../tests/video/test_video_module.py | 188 +++++++++++++++++- .../courseware/features/video.feature | 74 ------- 4 files changed, 255 insertions(+), 79 deletions(-) diff --git a/common/test/acceptance/pages/lms/course_nav.py b/common/test/acceptance/pages/lms/course_nav.py index 93ad20391d..84da21d6a7 100644 --- a/common/test/acceptance/pages/lms/course_nav.py +++ b/common/test/acceptance/pages/lms/course_nav.py @@ -195,3 +195,14 @@ class CourseNavPage(PageObject): Clean HTML of sequence titles, stripping out span tags and returning the first line. """ return self.REMOVE_SPAN_TAG_RE.sub('', element.get_attribute('innerHTML')).strip().split('\n')[0] + + def go_to_sequential_position(self, sequential_position): + """ + Within a section/subsection navigate to the sequential position specified by `sequential_position`. + + Arguments: + sequential_position (int): position in sequential bar + + """ + sequential_position_css = '#tab_{0}'.format(sequential_position - 1) + self.q(css=sequential_position_css).first.click() diff --git a/common/test/acceptance/pages/lms/video/video.py b/common/test/acceptance/pages/lms/video/video.py index 173ba9744e..554b05b6b5 100644 --- a/common/test/acceptance/pages/lms/video/video.py +++ b/common/test/acceptance/pages/lms/video/video.py @@ -33,7 +33,8 @@ CSS_CLASS_NAMES = { 'video_init': '.is-initialized', 'video_time': 'div.vidtime', 'video_display_name': '.vert h2', - 'captions_lang_list': '.langs-list li' + 'captions_lang_list': '.langs-list li', + 'video_speed': '.speeds .value' } VIDEO_MODES = { @@ -354,6 +355,20 @@ class VideoPage(PageObject): speed_selector = self.get_element_selector(video_display_name, 'li[data-speed="{speed}"] a'.format(speed=speed)) self.q(css=speed_selector).first.click() + def get_speed(self, video_display_name=None): + """ + Get current video speed value. + + Arguments: + video_display_name (str or None): Display name of a Video. + + Return: + str: speed value + + """ + speed_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_speed']) + return self.q(css=speed_selector).text[0] + def click_player_button(self, button, video_display_name=None): """ Click on `button`. @@ -701,11 +716,12 @@ class VideoPage(PageObject): def _wait_for(self, check_func, desc, result=False, timeout=200): """ - Calls the method provided as an argument until the return value is not False. + Calls the method provided as an argument until the Promise satisfied or BrokenPromise Arguments: check_func (callable): Function that accepts no arguments and returns a boolean indicating whether the promise is fulfilled. desc (str): Description of the Promise, used in log messages. + result (bool): Indicates whether we need a results from Promise or not timeout (float): Maximum number of seconds to wait for the Promise to be satisfied before timing out. """ @@ -756,3 +772,44 @@ class VideoPage(PageObject): js_code = "$('{seek_selector}').data('video-player-state').videoPlayer.onSlideSeek({{time: {seek_time}}})".format( seek_selector=seek_selector, seek_time=seek_time) self.browser.execute_script(js_code) + + def reload_page(self): + """ + Reload/Refresh the current video page. + """ + self.browser.refresh() + self.wait_for_video_player_render() + + def duration(self, video_display_name=None): + """ + Extract video duration. + + Arguments: + video_display_name (str or None): Display name of a Video. + + Returns: + str: duration in format min:sec + + """ + selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_time']) + + # The full time has the form "0:32 / 3:14" elapsed/duration + all_times = self.q(css=selector).text[0] + + duration_str = all_times.split('/')[1] + + return duration_str.strip() + + def wait_for_position(self, position, video_display_name=None): + """ + Wait until current will be equal to `position`. + + Arguments: + position (str): position we wait for. + video_display_name (str or None): Display name of a Video. + + """ + self._wait_for( + lambda: self.position(video_display_name) == position, + 'Position is {position}'.format(position=position) + ) diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py index 1cd57cdd4a..0838007300 100644 --- a/common/test/acceptance/tests/video/test_video_module.py +++ b/common/test/acceptance/tests/video/test_video_module.py @@ -222,12 +222,11 @@ class VideoBaseTest(UniqueCourseTest): return metadata - def open_video(self, video_display_name): + def go_to_sequential_position(self, position): """ Navigate to sequential specified by `video_display_name` - :param video_display_name (str): Sequential Title """ - self.course_nav.go_to_sequential(video_display_name) + self.course_nav.go_to_sequential_position(position) self.video.wait_for_video_player_render() @@ -525,6 +524,189 @@ class YouTubeVideoTest(VideoBaseTest): self.video.select_language('en') self.assertIn('Hi, welcome to Edx.', self.video.captions_text()) + def test_multiple_videos_in_sequentials_load_and_work(self): + """ + Scenario: Multiple videos in sequentials all load and work, switching between sequentials + Given it has videos "A,B" in "Youtube" mode in position "1" of sequential + And videos "E,F" in "Youtube" mode in position "2" of sequential + """ + self.verticals = [ + [{'display_name': 'A'}, {'display_name': 'B'}], [{'display_name': 'C'}, {'display_name': 'D'}] + ] + + tab1_video_names = ['A', 'B'] + tab2_video_names = ['C', 'D'] + + def execute_video_steps(video_names): + """ + Execute video steps + """ + for video_name in video_names: + self.video.click_player_button('play', video_name) + self.assertIn(self.video.state(video_name), ['playing', 'buffering']) + self.video.click_player_button('pause', video_name) + + # go to video + self.navigate_to_video() + + execute_video_steps(tab1_video_names) + + # go to second sequential position + self.go_to_sequential_position(2) + execute_video_steps(tab2_video_names) + + # go back to first sequential position + # we are again playing tab 1 videos to ensure that switching didn't broke some video functionality. + self.go_to_sequential_position(1) + execute_video_steps(tab1_video_names) + + def test_video_component_stores_speed_correctly_for_multiple_videos(self): + """ + Scenario: Video component stores speed correctly when each video is in separate sequential + Given I have a video "A" in "Youtube" mode in position "1" of sequential + And a video "B" in "Youtube" mode in position "2" of sequential + And a video "C" in "HTML5" mode in position "3" of sequential + """ + self.verticals = [ + [{'display_name': 'A'}], [{'display_name': 'B'}], + [{'display_name': 'C', 'metadata': self.metadata_for_mode('html5')}] + ] + + self.navigate_to_video() + + # select the "2.0" speed on video "A" + self.course_nav.go_to_sequential('A') + self.video.set_speed('2.0') + + # select the "0.50" speed on video "B" + self.course_nav.go_to_sequential('B') + self.video.set_speed('0.50') + + # open video "C" + self.course_nav.go_to_sequential('C') + + # check if video "C" should start playing at speed "0.75" + self.assertEqual(self.video.get_speed(), '0.75x') + + # open video "A" + self.course_nav.go_to_sequential('A') + + # check if video "A" should start playing at speed "2.0" + self.assertEqual(self.video.get_speed(), '2.0x') + + # reload the page + self.video.reload_page() + + # open video "A" + self.course_nav.go_to_sequential('A') + + # check if video "A" should start playing at speed "2.0" + self.assertEqual(self.video.get_speed(), '2.0x') + + # select the "1.0" speed on video "A" + self.video.set_speed('1.0') + + # open video "B" + self.course_nav.go_to_sequential('B') + + # check if video "B" should start playing at speed "0.50" + self.assertEqual(self.video.get_speed(), '0.50x') + + # open video "C" + self.course_nav.go_to_sequential('C') + + # check if video "C" should start playing at speed "1.0" + self.assertEqual(self.video.get_speed(), '1.0x') + + def test_video_has_correct_transcript(self): + """ + Scenario: Youtube video has correct transcript if fields for other speeds are filled + Given it has a video in "Youtube" mode + And I have uploaded multiple transcripts + And I make sure captions are opened + Then I see "Hi, welcome to Edx." text in the captions + And I select the "1.50" speed + And I reload the page with video + Then I see "Hi, welcome to Edx." text in the captions + And I see duration "1:56" + + """ + self.assets.extend(['subs_OEoXaMPEzfM.srt.sjson', 'subs_b7xgknqkQk8.srt.sjson']) + data = {'sub': 'OEoXaMPEzfM', 'youtube_id_1_5': 'b7xgknqkQk8'} + self.metadata = self.metadata_for_mode('youtube', additional_data=data) + + # go to video + self.navigate_to_video() + + self.video.show_captions() + + self.assertIn('Hi, welcome to Edx.', self.video.captions_text()) + + self.video.set_speed('1.50') + + self.video.reload_page() + + self.assertIn('Hi, welcome to Edx.', self.video.captions_text()) + + self.assertTrue(self.video.duration(), '1.56') + + def test_video_position_stored_correctly_wo_seek(self): + """ + Scenario: Video component stores position correctly when page is reloaded + Given the course has a Video component in "Youtube" mode + Then the video has rendered in "Youtube" mode + And I click video button "play"" + Then I wait until video reaches at position "0.05" + And I click video button "pause" + And I reload the page with video + And I click video button "play"" + And I click video button "pause" + Then video slider should be Equal or Greater than "0:05" + + """ + self.navigate_to_video() + + self.video.click_player_button('play') + + self.video.wait_for_position('0:05') + + self.video.click_player_button('pause') + + self.video.reload_page() + + self.video.click_player_button('play') + self.video.click_player_button('pause') + + self.assertGreaterEqual(int(self.video.position().split(':')[1]), 5) + + def test_video_position_stored_correctly_with_seek(self): + """ + Scenario: Video component stores position correctly when page is reloaded + Given the course has a Video component in "Youtube" mode + Then the video has rendered in "Youtube" mode + And I click video button "play"" + And I click video button "pause" + Then I seek video to "0:10" position + And I click video button "play"" + And I click video button "pause" + And I reload the page with video + Then video slider should be Equal or Greater than "0:10" + + """ + self.navigate_to_video() + + self.video.click_player_button('play') + self.video.click_player_button('pause') + + self.video.seek('0:10') + + self.video.click_player_button('play') + self.video.click_player_button('pause') + + self.video.reload_page() + + self.assertGreaterEqual(int(self.video.position().split(':')[1]), 10) + class YouTubeHtml5VideoTest(VideoBaseTest): """ Test YouTube HTML5 Video Player """ diff --git a/lms/djangoapps/courseware/features/video.feature b/lms/djangoapps/courseware/features/video.feature index 9e655e5a17..af5d2ff09f 100644 --- a/lms/djangoapps/courseware/features/video.feature +++ b/lms/djangoapps/courseware/features/video.feature @@ -3,68 +3,6 @@ Feature: LMS.Video component As a student, I want to view course videos in LMS # 1 - Scenario: Multiple videos in sequentials all load and work, switching between sequentials - Given I am registered for the course "test_course" - And it has a video "A" in "Youtube" mode in position "1" of sequential - And a video "B" in "HTML5" mode in position "1" of sequential - And a video "C" in "Youtube" mode in position "1" of sequential - And a video "D" in "Youtube" mode in position "1" of sequential - And a video "E" in "Youtube" mode in position "2" of sequential - And a video "F" in "Youtube" mode in position "2" of sequential - And a video "G" in "Youtube" mode in position "2" of sequential - And I open the section with videos - Then video "A" should start playing at speed "1.0" - And I select the "2.0" speed on video "B" - And I select the "2.0" speed on video "C" - And I select the "2.0" speed on video "D" - When I open video "E" - Then video "E" should start playing at speed "2.0" - And I select the "1.0" speed on video "F" - And I select the "1.0" speed on video "G" - When I open video "A" - Then video "A" should start playing at speed "2.0" - - # 2 - Scenario: Video component stores speed correctly when each video is in separate sequence - Given I am registered for the course "test_course" - And it has a video "A" in "Youtube" mode in position "1" of sequential - And a video "B" in "Youtube" mode in position "2" of sequential - And a video "C" in "HTML5" mode in position "3" of sequential - And I open the section with videos - And I select the "2.0" speed on video "A" - And I select the "0.50" speed on video "B" - When I open video "C" - Then video "C" should start playing at speed "0.75" - When I open video "A" - Then video "A" should start playing at speed "2.0" - And I reload the page with video - When I open video "A" - Then video "A" should start playing at speed "2.0" - And I select the "1.0" speed on video "A" - When I open video "B" - Then video "B" should start playing at speed "0.50" - When I open video "C" - Then video "C" should start playing at speed "1.0" - - # 9 -# Scenario: Youtube video has correct transcript if fields for other speeds are filled -# Given I am registered for the course "test_course" -# And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets -# And I have a "subs_b7xgknqkQk8.srt.sjson" transcript file in assets -# And it has a video in "Youtube" mode: -# | sub | youtube_id_1_5 | -# | OEoXaMPEzfM | b7xgknqkQk8 | -# And I make sure captions are opened -# Then I see "Hi, welcome to Edx." text in the captions -# And I select the "1.50" speed -# And I reload the page with video -# Then I see "Hi, welcome to Edx." text in the captions - # The 1:56 time is the duration from metadata. 1:54 time is the duration reported - # by the video API once the video starts playing. The next step is correct because - # "1:56" is the duration in the VCR timer before the video plays. -# And I see duration "1:56" - - # 3 Scenario: Verify that each video in each sub-section includes a transcript for non-Youtube countries Given youtube server is up and response time is 2 seconds And I am registered for the course "test_course" @@ -140,15 +78,3 @@ Feature: LMS.Video component # Then I select the "1.25" speed # And I click video button "pause" # And I click on caption line "2", video module shows elapsed time "4" - - # 31 Disabled 4/8/14 after intermittent failures in master - #Scenario: Video component stores position correctly when page is reloaded - # Given the course has a Video component in "Youtube" mode - # When the video has rendered in "Youtube" mode - # And I click video button "play" - # And I click video button "pause" - # Then I seek video to "0:10" position - # And I click video button "play" - # And I click video button "pause" - # And I reload the page with video - # Then I see video slider at "0:10" position