Merge pull request #3682 from edx/ammar/bok-choy-video-tests-batch9
Bok-Choy Video Tests Batch9
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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 """
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user