Bok-Choy video tests batch4
This commit is contained in:
@@ -102,7 +102,6 @@ class CourseNavPage(PageObject):
|
||||
self.q(css=subsection_css).first.click()
|
||||
self._on_section_promise(section_title, subsection_title).fulfill()
|
||||
|
||||
|
||||
def go_to_sequential(self, sequential_title):
|
||||
"""
|
||||
Within a section/subsection, navigate to the sequential with `sequential_title`.
|
||||
|
||||
@@ -8,7 +8,6 @@ from selenium.webdriver.common.action_chains import ActionChains
|
||||
from bok_choy.page_object import PageObject
|
||||
from bok_choy.promise import EmptyPromise, Promise
|
||||
from bok_choy.javascript import wait_for_js, js_defined
|
||||
from ...tests.helpers import wait_for_ajax
|
||||
|
||||
|
||||
VIDEO_BUTTONS = {
|
||||
@@ -18,6 +17,7 @@ VIDEO_BUTTONS = {
|
||||
'pause': '.video_control.pause',
|
||||
'fullscreen': '.add-fullscreen',
|
||||
'download_transcript': '.video-tracks > a',
|
||||
'speed': '.speeds'
|
||||
}
|
||||
|
||||
CSS_CLASS_NAMES = {
|
||||
@@ -31,12 +31,13 @@ CSS_CLASS_NAMES = {
|
||||
'video_spinner': '.video-wrapper .spinner',
|
||||
'video_xmodule': '.xmodule_VideoModule',
|
||||
'video_init': '.is-initialized',
|
||||
'video_time': 'div.vidtime'
|
||||
'video_time': 'div.vidtime',
|
||||
'video_display_name': '.vert h2'
|
||||
}
|
||||
|
||||
VIDEO_MODES = {
|
||||
'html5': 'video',
|
||||
'youtube': 'iframe'
|
||||
'html5': 'div.video video',
|
||||
'youtube': 'div.video iframe'
|
||||
}
|
||||
|
||||
VIDEO_MENUS = {
|
||||
@@ -60,20 +61,25 @@ class VideoPage(PageObject):
|
||||
return self.q(css='div{0}'.format(CSS_CLASS_NAMES['video_xmodule'])).present
|
||||
|
||||
@wait_for_js
|
||||
def _wait_for_element(self, element_css_selector, promise_desc):
|
||||
"""
|
||||
Wait for element specified by `element_css_selector` is present in DOM.
|
||||
:param element_css_selector: css selector of the element
|
||||
:param promise_desc: Description of the Promise, used in log messages.
|
||||
:return: BrokenPromise: the `Promise` was not satisfied within the time or attempt limits.
|
||||
# TODO(muhammad-ammar) Move this function to somewhere else so that others can use it also. # pylint: disable=W0511
|
||||
def _wait_for_element(self, element_selector, promise_desc):
|
||||
"""
|
||||
Wait for element specified by `element_selector` is present in DOM.
|
||||
|
||||
Arguments:
|
||||
element_selector (str): css selector of the element.
|
||||
promise_desc (str): Description of the Promise, used in log messages.
|
||||
|
||||
"""
|
||||
def _is_element_present():
|
||||
"""
|
||||
Check if web-element present in DOM
|
||||
:return: bool
|
||||
Check if web-element present in DOM.
|
||||
|
||||
Returns:
|
||||
bool: Tells elements presence.
|
||||
|
||||
"""
|
||||
return self.q(css=element_css_selector).present
|
||||
return self.q(css=element_selector).present
|
||||
|
||||
EmptyPromise(_is_element_present, promise_desc, timeout=200).fulfill()
|
||||
|
||||
@@ -81,16 +87,18 @@ class VideoPage(PageObject):
|
||||
def wait_for_video_class(self):
|
||||
"""
|
||||
Wait until element with class name `video` appeared in DOM.
|
||||
"""
|
||||
wait_for_ajax(self.browser)
|
||||
|
||||
video_css = '{0}'.format(CSS_CLASS_NAMES['video_container'])
|
||||
self._wait_for_element(video_css, 'Video is initialized')
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
|
||||
video_selector = '{0}'.format(CSS_CLASS_NAMES['video_container'])
|
||||
self._wait_for_element(video_selector, 'Video is initialized')
|
||||
|
||||
@wait_for_js
|
||||
def wait_for_video_player_render(self):
|
||||
"""
|
||||
Wait until Video Player Rendered Completely.
|
||||
|
||||
"""
|
||||
self.wait_for_video_class()
|
||||
self._wait_for_element(CSS_CLASS_NAMES['video_init'], 'Video Player Initialized')
|
||||
@@ -98,39 +106,95 @@ class VideoPage(PageObject):
|
||||
|
||||
def _is_finished_loading():
|
||||
"""
|
||||
Check if video loading completed
|
||||
:return: bool
|
||||
Check if video loading completed.
|
||||
|
||||
Returns:
|
||||
bool: Tells Video Finished Loading.
|
||||
|
||||
"""
|
||||
return not self.q(css=CSS_CLASS_NAMES['video_spinner']).visible
|
||||
|
||||
EmptyPromise(_is_finished_loading, 'Finished loading the video', timeout=200).fulfill()
|
||||
|
||||
wait_for_ajax(self.browser)
|
||||
self.wait_for_ajax()
|
||||
|
||||
def is_video_rendered(self, mode):
|
||||
def get_video_vertical_selector(self, video_display_name=None):
|
||||
"""
|
||||
Get selector for a video vertical with display name specified by `video_display_name`.
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video. Default vertical selector if None.
|
||||
|
||||
Returns:
|
||||
str: Vertical Selector for video.
|
||||
|
||||
"""
|
||||
if video_display_name:
|
||||
video_display_names = self.q(css=CSS_CLASS_NAMES['video_display_name']).text
|
||||
if video_display_name not in video_display_names:
|
||||
raise ValueError("Incorrect Video Display Name: '{0}'".format(video_display_name))
|
||||
return '.vert.vert-{}'.format(video_display_names.index(video_display_name))
|
||||
else:
|
||||
return '.vert.vert-0'
|
||||
|
||||
def get_element_selector(self, video_display_name, class_name):
|
||||
"""
|
||||
Construct unique element selector.
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
class_name (str): css class name for an element.
|
||||
|
||||
Returns:
|
||||
str: Element Selector.
|
||||
|
||||
"""
|
||||
return '{vertical} {video_element}'.format(
|
||||
vertical=self.get_video_vertical_selector(video_display_name),
|
||||
video_element=class_name)
|
||||
|
||||
def is_video_rendered(self, mode, video_display_name=None):
|
||||
"""
|
||||
Check that if video is rendered in `mode`.
|
||||
:param mode: Video mode, `html5` or `youtube`
|
||||
|
||||
Arguments:
|
||||
mode (str): Video mode, `html5` or `youtube`.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Tells if video is rendered in `mode`.
|
||||
|
||||
"""
|
||||
html_tag = VIDEO_MODES[mode]
|
||||
css = '{0} {1}'.format(CSS_CLASS_NAMES['video_container'], html_tag)
|
||||
selector = self.get_element_selector(video_display_name, VIDEO_MODES[mode])
|
||||
|
||||
def _is_element_present():
|
||||
"""
|
||||
Check if a web element is present in DOM
|
||||
:return:
|
||||
Check if a web element is present in DOM.
|
||||
|
||||
Returns:
|
||||
tuple: (is_satisfied, result)`, where `is_satisfied` is a boolean indicating whether the promise was
|
||||
satisfied, and `result` is a value to return from the fulfilled `Promise`.
|
||||
|
||||
"""
|
||||
is_present = self.q(css=css).present
|
||||
is_present = self.q(css=selector).present
|
||||
return is_present, is_present
|
||||
|
||||
return Promise(_is_element_present, 'Video Rendering Failed in {0} mode.'.format(mode)).fulfill()
|
||||
|
||||
@property
|
||||
def is_autoplay_enabled(self):
|
||||
def is_autoplay_enabled(self, video_display_name=None):
|
||||
"""
|
||||
Extract `data-autoplay` attribute to check video autoplay is enabled or disabled.
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Tells if autoplay enabled/disabled.
|
||||
|
||||
"""
|
||||
auto_play = self.q(css=CSS_CLASS_NAMES['video_container']).attrs('data-autoplay')[0]
|
||||
selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_container'])
|
||||
auto_play = self.q(css=selector).attrs('data-autoplay')[0]
|
||||
|
||||
if auto_play.lower() == 'false':
|
||||
return False
|
||||
@@ -138,129 +202,213 @@ class VideoPage(PageObject):
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_error_message_shown(self):
|
||||
def is_error_message_shown(self, video_display_name=None):
|
||||
"""
|
||||
Checks if video player error message shown.
|
||||
:return: bool
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Tells about error message visibility.
|
||||
|
||||
"""
|
||||
return self.q(css=CSS_CLASS_NAMES['error_message']).visible
|
||||
selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['error_message'])
|
||||
return self.q(css=selector).visible
|
||||
|
||||
@property
|
||||
def error_message_text(self):
|
||||
def error_message_text(self, video_display_name=None):
|
||||
"""
|
||||
Extract video player error message text.
|
||||
:return: str
|
||||
"""
|
||||
return self.q(css=CSS_CLASS_NAMES['error_message']).text[0]
|
||||
|
||||
def is_button_shown(self, button_id):
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
str: Error message text.
|
||||
|
||||
"""
|
||||
Check if a video button specified by `button_id` is visible
|
||||
:param button_id: button css selector
|
||||
:return: bool
|
||||
selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['error_message'])
|
||||
return self.q(css=selector).text[0]
|
||||
|
||||
def is_button_shown(self, button_id, video_display_name=None):
|
||||
"""
|
||||
return self.q(css=VIDEO_BUTTONS[button_id]).visible
|
||||
Check if a video button specified by `button_id` is visible.
|
||||
|
||||
Arguments:
|
||||
button_id (str): key in VIDEO_BUTTONS dictionary, its value will give us the css selector for button.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Tells about a buttons visibility.
|
||||
|
||||
"""
|
||||
selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS[button_id])
|
||||
return self.q(css=selector).visible
|
||||
|
||||
@wait_for_js
|
||||
def show_captions(self):
|
||||
def show_captions(self, video_display_name=None):
|
||||
"""
|
||||
Show the video captions.
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
"""
|
||||
subtitle_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['closed_captions'])
|
||||
|
||||
def _is_subtitles_open():
|
||||
"""
|
||||
Check if subtitles are opened
|
||||
:return: bool
|
||||
|
||||
Returns:
|
||||
bool: Subtitles Visibility
|
||||
|
||||
"""
|
||||
is_open = not self.q(css=CSS_CLASS_NAMES['closed_captions']).present
|
||||
is_open = not self.q(css=subtitle_selector).present
|
||||
return is_open
|
||||
|
||||
# Make sure that the CC button is there
|
||||
EmptyPromise(lambda: self.is_button_shown('CC'),
|
||||
EmptyPromise(lambda: self.is_button_shown('CC', video_display_name),
|
||||
"CC button is shown").fulfill()
|
||||
|
||||
# Check if the captions are already open and click if not
|
||||
if _is_subtitles_open() is False:
|
||||
self.q(css=VIDEO_BUTTONS['CC']).first.click()
|
||||
self.click_player_button('CC', video_display_name)
|
||||
|
||||
# Verify that they are now open
|
||||
EmptyPromise(_is_subtitles_open,
|
||||
"Subtitles are shown").fulfill()
|
||||
|
||||
@property
|
||||
def captions_text(self):
|
||||
def captions_text(self, video_display_name=None):
|
||||
"""
|
||||
Extract captions text.
|
||||
:return: str
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
str: Captions Text.
|
||||
|
||||
"""
|
||||
# wait until captions rendered completely
|
||||
self._wait_for_element(CSS_CLASS_NAMES['captions_rendered'], 'Captions Rendered')
|
||||
captions_rendered_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['captions_rendered'])
|
||||
self._wait_for_element(captions_rendered_selector, 'Captions Rendered')
|
||||
|
||||
captions_css = CSS_CLASS_NAMES['captions_text']
|
||||
|
||||
subs = self.q(css=captions_css).html
|
||||
captions_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['captions_text'])
|
||||
subs = self.q(css=captions_selector).html
|
||||
|
||||
return ' '.join(subs)
|
||||
|
||||
def set_speed(self, speed):
|
||||
def set_speed(self, speed, video_display_name=None):
|
||||
"""
|
||||
Change the video play speed.
|
||||
:param speed: speed value in str
|
||||
|
||||
Arguments:
|
||||
speed (str): Video speed value
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
"""
|
||||
self.browser.execute_script("$('.speeds').addClass('is-opened')")
|
||||
speed_css = 'li[data-speed="{0}"] a'.format(speed)
|
||||
# mouse over to video speed button
|
||||
speed_menu_selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS['speed'])
|
||||
element_to_hover_over = self.q(css=speed_menu_selector).results[0]
|
||||
hover = ActionChains(self.browser).move_to_element(element_to_hover_over)
|
||||
hover.perform()
|
||||
|
||||
EmptyPromise(lambda: self.q(css='.speeds').visible, 'Video Speed Control Shown').fulfill()
|
||||
speed_selector = self.get_element_selector(video_display_name, 'li[data-speed="{speed}"] a'.format(speed=speed))
|
||||
self.q(css=speed_selector).first.click()
|
||||
|
||||
self.q(css=speed_css).first.click()
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Get current video speed value.
|
||||
:return: str
|
||||
"""
|
||||
speed_css = '.speeds .value'
|
||||
return self.q(css=speed_css).text[0]
|
||||
|
||||
speed = property(get_speed, set_speed)
|
||||
|
||||
def click_player_button(self, button):
|
||||
def click_player_button(self, button, video_display_name=None):
|
||||
"""
|
||||
Click on `button`.
|
||||
:param button: key in VIDEO_BUTTONS dictionary, its value will give us the css selector for `button`
|
||||
|
||||
Arguments:
|
||||
button (str): key in VIDEO_BUTTONS dictionary, its value will give us the css selector for `button`
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
"""
|
||||
self.q(css=VIDEO_BUTTONS[button]).first.click()
|
||||
wait_for_ajax(self.browser)
|
||||
button_selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS[button])
|
||||
self.q(css=button_selector).first.click()
|
||||
|
||||
if button == 'play':
|
||||
# wait for video buffering
|
||||
self._wait_for_video_play(video_display_name)
|
||||
|
||||
self.wait_for_ajax()
|
||||
|
||||
def _wait_for_video_play(self, video_display_name=None):
|
||||
"""
|
||||
Wait until video starts playing
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
"""
|
||||
playing_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_container'])
|
||||
pause_selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS['pause'])
|
||||
|
||||
def _check_promise():
|
||||
"""
|
||||
Promise check
|
||||
|
||||
Returns:
|
||||
bool: Is promise satisfied.
|
||||
|
||||
"""
|
||||
return 'is-playing' in self.q(css=playing_selector).attrs('class')[0] and self.q(css=pause_selector).present
|
||||
|
||||
EmptyPromise(_check_promise, 'Video is Playing', timeout=200).fulfill()
|
||||
|
||||
def _get_element_dimensions(self, selector):
|
||||
"""
|
||||
Gets the width and height of element specified by `selector`
|
||||
:param selector: str, css selector of a web element
|
||||
:return: dict
|
||||
|
||||
Arguments:
|
||||
selector (str): css selector of a web element
|
||||
|
||||
Returns:
|
||||
dict: Dimensions of a web element.
|
||||
|
||||
"""
|
||||
element = self.q(css=selector).results[0]
|
||||
return element.size
|
||||
|
||||
def _get_dimensions(self):
|
||||
def _get_dimensions(self, video_display_name=None):
|
||||
"""
|
||||
Gets the video player dimensions
|
||||
:return: tuple
|
||||
Gets the video player dimensions.
|
||||
|
||||
Arguments:
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
tuple: Dimensions
|
||||
|
||||
"""
|
||||
video = self._get_element_dimensions('.video-player iframe, .video-player video')
|
||||
wrapper = self._get_element_dimensions('.tc-wrapper')
|
||||
controls = self._get_element_dimensions('.video-controls')
|
||||
progress_slider = self._get_element_dimensions('.video-controls > .slider')
|
||||
iframe_selector = self.get_element_selector(video_display_name, '.video-player iframe,')
|
||||
video_selector = self.get_element_selector(video_display_name, ' .video-player video')
|
||||
video = self._get_element_dimensions(iframe_selector + video_selector)
|
||||
wrapper = self._get_element_dimensions(self.get_element_selector(video_display_name, '.tc-wrapper'))
|
||||
controls = self._get_element_dimensions(self.get_element_selector(video_display_name, '.video-controls'))
|
||||
progress_slider = self._get_element_dimensions(
|
||||
self.get_element_selector(video_display_name, '.video-controls > .slider'))
|
||||
|
||||
expected = dict(wrapper)
|
||||
expected['height'] -= controls['height'] + 0.5 * progress_slider['height']
|
||||
|
||||
return video, expected
|
||||
|
||||
def is_aligned(self, is_transcript_visible):
|
||||
def is_aligned(self, is_transcript_visible, video_display_name=None):
|
||||
"""
|
||||
Check if video is aligned properly.
|
||||
:param is_transcript_visible: bool
|
||||
:return: bool
|
||||
|
||||
Arguments:
|
||||
is_transcript_visible (bool): Transcript is visible or not.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Alignment result.
|
||||
|
||||
"""
|
||||
# Width of the video container in css equal 75% of window if transcript enabled
|
||||
wrapper_width = 75 if is_transcript_visible else 100
|
||||
@@ -272,7 +420,7 @@ class VideoPage(PageObject):
|
||||
# Currently there is no other way to wait instead of explicit wait
|
||||
time.sleep(0.2)
|
||||
|
||||
real, expected = self._get_dimensions()
|
||||
real, expected = self._get_dimensions(video_display_name)
|
||||
|
||||
width = round(100 * real['width'] / expected['width']) == wrapper_width
|
||||
|
||||
@@ -282,7 +430,7 @@ class VideoPage(PageObject):
|
||||
# Currently there is no other way to wait instead of explicit wait
|
||||
time.sleep(0.2)
|
||||
|
||||
real, expected = self._get_dimensions()
|
||||
real, expected = self._get_dimensions(video_display_name)
|
||||
|
||||
height = abs(expected['height'] - real['height']) <= 5
|
||||
|
||||
@@ -295,7 +443,8 @@ class VideoPage(PageObject):
|
||||
|
||||
def _get_transcript(self, url):
|
||||
"""
|
||||
Sends a http get request.
|
||||
Download Transcript from `url`
|
||||
|
||||
"""
|
||||
kwargs = dict()
|
||||
|
||||
@@ -308,53 +457,140 @@ class VideoPage(PageObject):
|
||||
response = requests.get(url, **kwargs)
|
||||
return response.status_code < 400, response.headers, response.content
|
||||
|
||||
def downloaded_transcript_contains_text(self, transcript_format, text_to_search):
|
||||
def downloaded_transcript_contains_text(self, transcript_format, text_to_search, video_display_name=None):
|
||||
"""
|
||||
Download the transcript in format `transcript_format` and check that it contains the text `text_to_search`
|
||||
:param transcript_format: `srt` or `txt`
|
||||
:param text_to_search: str
|
||||
:return: bool
|
||||
|
||||
Arguments:
|
||||
transcript_format (str): Transcript file format `srt` or `txt`
|
||||
text_to_search (str): Text to search in Transcript.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Transcript download result.
|
||||
|
||||
"""
|
||||
transcript_selector = self.get_element_selector(video_display_name, VIDEO_MENUS['transcript-format'])
|
||||
|
||||
# check if we have a transcript with correct format
|
||||
assert '.' + transcript_format in self.q(css=VIDEO_MENUS['transcript-format']).text[0]
|
||||
if '.' + transcript_format not in self.q(css=transcript_selector).text[0]:
|
||||
return False
|
||||
|
||||
formats = {
|
||||
'srt': 'application/x-subrip',
|
||||
'txt': 'text/plain',
|
||||
}
|
||||
|
||||
url = self.q(css=VIDEO_BUTTONS['download_transcript']).attrs('href')[0]
|
||||
transcript_url_selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS['download_transcript'])
|
||||
url = self.q(css=transcript_url_selector).attrs('href')[0]
|
||||
result, headers, content = self._get_transcript(url)
|
||||
|
||||
assert result
|
||||
assert formats[transcript_format] in headers.get('content-type', '')
|
||||
assert text_to_search in content.decode('utf-8')
|
||||
if result is False:
|
||||
return False
|
||||
|
||||
def select_language(self, code):
|
||||
"""
|
||||
Select captions for language `code`
|
||||
:param code: str, two character language code like `en`, `zh`
|
||||
:return: bool, True for Success, False for Failure or BrokenPromise
|
||||
"""
|
||||
wait_for_ajax(self.browser)
|
||||
if formats[transcript_format] not in headers.get('content-type', ''):
|
||||
return False
|
||||
|
||||
selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format(code=code)
|
||||
if text_to_search not in content.decode('utf-8'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def select_language(self, code, video_display_name=None):
|
||||
"""
|
||||
Select captions for language `code`.
|
||||
|
||||
Arguments:
|
||||
code (str): two character language code like `en`, `zh`.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
|
||||
# mouse over to CC button
|
||||
element_to_hover_over = self.q(css=VIDEO_BUTTONS["CC"]).results[0]
|
||||
cc_button_selector = self.get_element_selector(video_display_name, VIDEO_BUTTONS["CC"])
|
||||
element_to_hover_over = self.q(css=cc_button_selector).results[0]
|
||||
hover = ActionChains(self.browser).move_to_element(element_to_hover_over)
|
||||
hover.perform()
|
||||
|
||||
self.q(css=selector).first.click()
|
||||
language_selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format(code=code)
|
||||
language_selector = self.get_element_selector(video_display_name, language_selector)
|
||||
self.q(css=language_selector).first.click()
|
||||
|
||||
assert 'is-active' == self.q(css=selector).attrs('class')[0]
|
||||
assert len(self.q(css=VIDEO_MENUS["language"] + ' li.is-active').results) == 1
|
||||
if 'is-active' != self.q(css=language_selector).attrs('class')[0]:
|
||||
return False
|
||||
|
||||
active_lang_selector = self.get_element_selector(video_display_name, VIDEO_MENUS["language"] + ' li.is-active')
|
||||
if len(self.q(css=active_lang_selector).results) != 1:
|
||||
return False
|
||||
|
||||
# Make sure that all ajax requests that affects the display of captions are finished.
|
||||
# For example, request to get new translation etc.
|
||||
wait_for_ajax(self.browser)
|
||||
self.wait_for_ajax()
|
||||
|
||||
EmptyPromise(lambda: self.q(css=CSS_CLASS_NAMES['captions']).visible, 'Subtitles Visible').fulfill()
|
||||
captions_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['captions'])
|
||||
EmptyPromise(lambda: self.q(css=captions_selector).visible, 'Subtitles Visible').fulfill()
|
||||
|
||||
# wait until captions rendered completely
|
||||
self._wait_for_element(CSS_CLASS_NAMES['captions_rendered'], 'Captions Rendered')
|
||||
captions_rendered_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['captions_rendered'])
|
||||
self._wait_for_element(captions_rendered_selector, 'Captions Rendered')
|
||||
|
||||
return True
|
||||
|
||||
def is_menu_exist(self, menu_name, video_display_name=None):
|
||||
"""
|
||||
Check if menu `menu_name` exists.
|
||||
|
||||
Arguments:
|
||||
menu_name (str): Menu key from VIDEO_MENUS.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Menu existence result
|
||||
|
||||
"""
|
||||
selector = self.get_element_selector(video_display_name, VIDEO_MENUS[menu_name])
|
||||
return self.q(css=selector).present
|
||||
|
||||
def select_transcript_format(self, transcript_format, video_display_name=None):
|
||||
"""
|
||||
Select transcript with format `transcript_format`.
|
||||
|
||||
Arguments:
|
||||
transcript_format (st): Transcript file format `srt` or `txt`.
|
||||
video_display_name (str or None): Display name of a Video.
|
||||
|
||||
Returns:
|
||||
bool: Selection Result.
|
||||
|
||||
"""
|
||||
button_selector = self.get_element_selector(video_display_name, VIDEO_MENUS['transcript-format'])
|
||||
|
||||
button = self.q(css=button_selector).results[0]
|
||||
|
||||
coord_y = button.location_once_scrolled_into_view['y']
|
||||
self.browser.execute_script("window.scrollTo(0, {});".format(coord_y))
|
||||
|
||||
hover = ActionChains(self.browser).move_to_element(button)
|
||||
hover.perform()
|
||||
|
||||
if '...' not in self.q(css=button_selector).text[0]:
|
||||
return False
|
||||
|
||||
menu_selector = self.get_element_selector(video_display_name, VIDEO_MENUS['download_transcript'])
|
||||
menu_items = self.q(css=menu_selector + ' a').results
|
||||
for item in menu_items:
|
||||
if item.get_attribute('data-value') == transcript_format:
|
||||
item.click()
|
||||
self.wait_for_ajax()
|
||||
break
|
||||
|
||||
self.browser.execute_script("window.scrollTo(0, 0);")
|
||||
|
||||
if self.q(css=menu_selector + ' .active a').attrs('data-value')[0] != transcript_format:
|
||||
return False
|
||||
|
||||
if '.' + transcript_format not in self.q(css=button_selector).text[0]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -6,26 +6,6 @@ from bok_choy.web_app_test import WebAppTest
|
||||
from bok_choy.promise import EmptyPromise
|
||||
|
||||
|
||||
def wait_for_ajax(browser, try_limit=None, try_interval=0.5, timeout=60):
|
||||
"""
|
||||
Make sure that all ajax requests are finished.
|
||||
:param try_limit (int or None): Number of attempts to make to satisfy the `Promise`. Can be `None` to
|
||||
disable the limit.
|
||||
:param try_interval (float): Number of seconds to wait between attempts.
|
||||
:param timeout (float): Maximum number of seconds to wait for the `Promise` to be satisfied before timing out.
|
||||
:param browser: selenium.webdriver, The Selenium-controlled browser that this page is loaded in.
|
||||
"""
|
||||
def _is_ajax_finished():
|
||||
"""
|
||||
Check if all the ajax call on current page completed.
|
||||
:return:
|
||||
"""
|
||||
return browser.execute_script("return jQuery.active") == 0
|
||||
|
||||
EmptyPromise(_is_ajax_finished, "Finished waiting for ajax requests.", try_limit=try_limit,
|
||||
try_interval=try_interval, timeout=timeout).fulfill()
|
||||
|
||||
|
||||
def load_data_str(rel_path):
|
||||
"""
|
||||
Load a file from the "data" directory as a string.
|
||||
|
||||
@@ -319,7 +319,7 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "好 各位同学"
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
self.video.downloaded_transcript_contains_text('srt', unicode_text)
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', unicode_text))
|
||||
|
||||
def test_download_button_two_transcript_languages(self):
|
||||
"""
|
||||
@@ -343,10 +343,10 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "Hi, welcome to Edx."
|
||||
self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.')
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.'))
|
||||
|
||||
# select language with code "zh"
|
||||
self.video.select_language('zh')
|
||||
self.assertTrue(self.video.select_language('zh'))
|
||||
|
||||
# check if we see "好 各位同学" text in the captions
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
@@ -354,7 +354,7 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "好 各位同学"
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
self.video.downloaded_transcript_contains_text('srt', unicode_text)
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', unicode_text))
|
||||
|
||||
def test_fullscreen_video_alignment_on_transcript_toggle(self):
|
||||
"""
|
||||
@@ -437,6 +437,59 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
|
||||
self.assertTrue(self.video.is_video_rendered('html5'))
|
||||
|
||||
def test_download_transcript_button_works_correctly(self):
|
||||
"""
|
||||
Scenario: Download Transcript button works correctly
|
||||
Given the course has Video components A and B in "Youtube" mode
|
||||
And Video component C in "HTML5" mode
|
||||
And I have defined downloadable transcripts for the videos
|
||||
Then I can download a transcript for Video A in "srt" format
|
||||
And I can download a transcript for Video A in "txt" format
|
||||
And I can download a transcript for Video B in "txt" format
|
||||
And the Download Transcript menu does not exist for Video C
|
||||
"""
|
||||
|
||||
data_a = {'sub': 'OEoXaMPEzfM', 'download_track': True}
|
||||
youtube_a_metadata = self.metadata_for_mode('youtube', additional_data=data_a)
|
||||
self.assets.append('subs_OEoXaMPEzfM.srt.sjson')
|
||||
|
||||
data_b = {'youtube_id_1_0': 'b7xgknqkQk8', 'sub': 'b7xgknqkQk8', 'download_track': True}
|
||||
youtube_b_metadata = self.metadata_for_mode('youtube', additional_data=data_b)
|
||||
self.assets.append('subs_b7xgknqkQk8.srt.sjson')
|
||||
|
||||
data_c = {'track': 'http://example.org/', 'download_track': True}
|
||||
html5_c_metadata = self.metadata_for_mode('html5', additional_data=data_c)
|
||||
|
||||
self.verticals = [
|
||||
[{'display_name': 'A', 'metadata': youtube_a_metadata}],
|
||||
[{'display_name': 'B', 'metadata': youtube_b_metadata}],
|
||||
[{'display_name': 'C', 'metadata': html5_c_metadata}]
|
||||
]
|
||||
|
||||
# open the section with videos (open video "A")
|
||||
self.navigate_to_video()
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "00:00:00,270"
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', '00:00:00,270'))
|
||||
|
||||
# select the transcript format "txt"
|
||||
self.assertTrue(self.video.select_transcript_format('txt'))
|
||||
|
||||
# check if we can download transcript in "txt" format that has text "Hi, welcome to Edx."
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('txt', 'Hi, welcome to Edx.'))
|
||||
|
||||
# open video "B"
|
||||
self.course_nav.go_to_sequential('B')
|
||||
|
||||
# check if we can download transcript in "txt" format that has text "Equal transcripts"
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('txt', 'Equal transcripts'))
|
||||
|
||||
# open video "C"
|
||||
self.course_nav.go_to_sequential('C')
|
||||
|
||||
# menu "download_transcript" doesn't exist
|
||||
self.assertFalse(self.video.is_menu_exist('download_transcript'))
|
||||
|
||||
|
||||
class YouTubeHtml5VideoTest(VideoBaseTest):
|
||||
""" Test YouTube HTML5 Video Player """
|
||||
@@ -517,7 +570,7 @@ class Html5VideoTest(VideoBaseTest):
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "好 各位同学"
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
self.video.downloaded_transcript_contains_text('srt', unicode_text)
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', unicode_text))
|
||||
|
||||
def test_download_button_two_transcript_languages(self):
|
||||
"""
|
||||
@@ -541,10 +594,10 @@ class Html5VideoTest(VideoBaseTest):
|
||||
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
|
||||
|
||||
# check if we can download transcript in "srt" format that has text "Hi, welcome to Edx."
|
||||
self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.')
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.'))
|
||||
|
||||
# select language with code "zh"
|
||||
self.video.select_language('zh')
|
||||
self.assertTrue(self.video.select_language('zh'))
|
||||
|
||||
# check if we see "好 各位同学" text in the captions
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
@@ -553,7 +606,7 @@ class Html5VideoTest(VideoBaseTest):
|
||||
|
||||
#Then I can download transcript in "srt" format that has text "好 各位同学"
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
self.video.downloaded_transcript_contains_text('srt', unicode_text)
|
||||
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', unicode_text))
|
||||
|
||||
def test_full_screen_video_alignment_with_transcript_visible(self):
|
||||
"""
|
||||
|
||||
@@ -67,28 +67,6 @@ Feature: LMS.Video component
|
||||
And I select language with code "en"
|
||||
And I see "Hi, welcome to Edx." text in the captions
|
||||
|
||||
# 5
|
||||
Scenario: Download Transcript button works correctly in Video component
|
||||
Given I am registered for the course "test_course"
|
||||
And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
|
||||
And it has a video "A" in "Youtube" mode in position "1" of sequential:
|
||||
| sub | download_track |
|
||||
| OEoXaMPEzfM | true |
|
||||
And a video "B" in "Youtube" mode in position "2" of sequential:
|
||||
| sub | download_track |
|
||||
| OEoXaMPEzfM | true |
|
||||
And a video "C" in "Youtube" mode in position "3" of sequential:
|
||||
| track | download_track |
|
||||
| http://example.org/ | true |
|
||||
And I open the section with videos
|
||||
Then I can download transcript in "srt" format that has text "00:00:00,270"
|
||||
And I select the transcript format "txt"
|
||||
Then I can download transcript in "txt" format that has text "Hi, welcome to Edx."
|
||||
When I open video "B"
|
||||
Then I can download transcript in "txt" format that has text "Hi, welcome to Edx."
|
||||
When I open video "C"
|
||||
Then menu "download_transcript" doesn't exist
|
||||
|
||||
# 9
|
||||
# Scenario: Youtube video has correct transcript if fields for other speeds are filled
|
||||
# Given I am registered for the course "test_course"
|
||||
|
||||
Reference in New Issue
Block a user