From af6c5efbb3b2e483b39668bde675b71b0bb50edc Mon Sep 17 00:00:00 2001 From: Muhammad Ammar Date: Thu, 8 May 2014 10:45:39 +0000 Subject: [PATCH] Bok-Choy video tests batch4 --- .../test/acceptance/pages/lms/course_nav.py | 1 - common/test/acceptance/pages/lms/video.py | 460 +++++++++++++----- common/test/acceptance/tests/helpers.py | 20 - .../acceptance/tests/test_video_module.py | 69 ++- .../courseware/features/video.feature | 22 - 5 files changed, 409 insertions(+), 163 deletions(-) diff --git a/common/test/acceptance/pages/lms/course_nav.py b/common/test/acceptance/pages/lms/course_nav.py index 709ecebdb6..93ad20391d 100644 --- a/common/test/acceptance/pages/lms/course_nav.py +++ b/common/test/acceptance/pages/lms/course_nav.py @@ -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`. diff --git a/common/test/acceptance/pages/lms/video.py b/common/test/acceptance/pages/lms/video.py index fe07f4d1ba..e4a76e36d4 100644 --- a/common/test/acceptance/pages/lms/video.py +++ b/common/test/acceptance/pages/lms/video.py @@ -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 diff --git a/common/test/acceptance/tests/helpers.py b/common/test/acceptance/tests/helpers.py index 12228344a0..1d568504c5 100644 --- a/common/test/acceptance/tests/helpers.py +++ b/common/test/acceptance/tests/helpers.py @@ -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. diff --git a/common/test/acceptance/tests/test_video_module.py b/common/test/acceptance/tests/test_video_module.py index 8a5dd95e9e..ad33afb98a 100644 --- a/common/test/acceptance/tests/test_video_module.py +++ b/common/test/acceptance/tests/test_video_module.py @@ -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): """ diff --git a/lms/djangoapps/courseware/features/video.feature b/lms/djangoapps/courseware/features/video.feature index ea70857370..98890218dd 100644 --- a/lms/djangoapps/courseware/features/video.feature +++ b/lms/djangoapps/courseware/features/video.feature @@ -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"