From f93e4f2775fb6280d1f6579c833f527dc3648aa8 Mon Sep 17 00:00:00 2001 From: Muhammad Ammar Date: Mon, 11 Aug 2014 11:07:33 +0000 Subject: [PATCH] Bok-Choy CMS Video Editor Tests --- .../features/video_editor.feature | 241 --------- .../test/acceptance/pages/lms/video/video.py | 15 +- .../acceptance/pages/studio/video/video.py | 294 ++++++++++- .../tests/video/test_studio_video_editor.py | 490 ++++++++++++++++++ .../tests/video/test_studio_video_module.py | 7 +- .../tests/video/test_video_module.py | 3 +- 6 files changed, 771 insertions(+), 279 deletions(-) delete mode 100644 cms/djangoapps/contentstore/features/video_editor.feature create mode 100644 common/test/acceptance/tests/video/test_studio_video_editor.py diff --git a/cms/djangoapps/contentstore/features/video_editor.feature b/cms/djangoapps/contentstore/features/video_editor.feature deleted file mode 100644 index 48bdd4a4b4..0000000000 --- a/cms/djangoapps/contentstore/features/video_editor.feature +++ /dev/null @@ -1,241 +0,0 @@ -@shard_1 @requires_stub_youtube -Feature: CMS Video Component Editor - As a course author, I want to be able to create video components - - # 1 - Scenario: User can view Video metadata - Given I have created a Video component - And I edit the component - Then I see the correct video settings and default values - - # 2 - # Safari has trouble saving values on Sauce - @skip_safari - Scenario: User can modify Video display name - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - Then I can modify video display name - And my video display name change is persisted on save - - # 3 - # Sauce Labs cannot delete cookies - @skip_sauce - Scenario: Captions are hidden when "transcript display" is false - Given I have created a Video component with subtitles - And I have set "transcript display" to False - Then when I view the video it does not show the captions - - # 4 - # Sauce Labs cannot delete cookies - @skip_sauce - Scenario: Captions are shown when "transcript display" is true - Given I have created a Video component with subtitles - And I have set "transcript display" to True - Then when I view the video it does show the captions - - # 5 - Scenario: Translations uploading works correctly - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "chinese_transcripts.srt" for "zh" language code - And I save changes - Then when I view the video it does show the captions - And I see "好 各位同学" text in the captions - And I edit the component - And I open tab "Advanced" - And I see translations for "zh" - And I upload transcript file "uk_transcripts.srt" for "uk" language code - And I save changes - Then when I view the video it does show the captions - And I see "好 各位同学" text in the captions - And video language menu has "uk, zh" translations - - # 6 - Scenario: User can upload transcript file with > 1mb size - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "1mb_transcripts.srt" for "uk" language code - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - - # 7 - Scenario: Translations downloading works correctly w/ preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |zh |chinese_transcripts.srt| - And I save changes - And I edit the component - And I open tab "Advanced" - And I see translations for "uk, zh" - And video language menu has "uk, zh" translations - Then I can download transcript for "zh" language code, that contains text "好 各位同学" - And I can download transcript for "uk" language code, that contains text "Привіт, edX вітає вас." - - # 8 - Scenario: Translations downloading works correctly w/o preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |zh |chinese_transcripts.srt| - Then I can download transcript for "zh" language code, that contains text "好 各位同学" - And I can download transcript for "uk" language code, that contains text "Привіт, edX вітає вас." - - # 9 - Scenario: Translations removing works correctly w/ preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |zh |chinese_transcripts.srt| - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - And video language menu has "uk, zh" translations - And I edit the component - And I open tab "Advanced" - And I see translations for "uk, zh" - Then I remove translation for "uk" language code - And I save changes - Then when I view the video it does show the captions - And I see "好 各位同学" text in the captions - And I edit the component - And I open tab "Advanced" - And I see translations for "zh" - Then I remove translation for "zh" language code - And I save changes - Then when I view the video it does not show the captions - - # 10 - Scenario: Translations removing works correctly w/o preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "uk_transcripts.srt" for "uk" language code - And I see translations for "uk" - Then I remove translation for "uk" language code - And I save changes - Then when I view the video it does not show the captions - - # 11 - Scenario: Translations clearing works correctly w/ preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |zh |chinese_transcripts.srt| - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - And video language menu has "uk, zh" translations - And I edit the component - And I open tab "Advanced" - And I see translations for "uk, zh" - And I click button "Clear" - And I save changes - Then when I view the video it does not show the captions - - # 12 - Scenario: Translations clearing works correctly w/o preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |zh |chinese_transcripts.srt| - And I click button "Clear" - And I save changes - Then when I view the video it does not show the captions - - # 13 - Scenario: User cannot upload translations in sjson format - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I click button "Add" - And I choose "uk" language code - And I try to upload transcript file "uk_transcripts.sjson" - Then I see validation error "Only SRT files can be uploaded. Please select a file ending in .srt to upload." - - # 14 - Scenario: User can easy replace the translation by another one w/ preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "chinese_transcripts.srt" for "zh" language code - And I save changes - Then when I view the video it does show the captions - And I see "好 各位同学" text in the captions - And I edit the component - And I open tab "Advanced" - And I see translations for "zh" - And I replace transcript file for "zh" language code by "uk_transcripts.srt" - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - - # 15 - Scenario: User can easy replace the translation by another one w/o preliminary saving - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "chinese_transcripts.srt" for "zh" language code - And I see translations for "zh" - And I replace transcript file for "zh" language code by "uk_transcripts.srt" - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - - # 16 - Scenario: Upload "zh" file "A" -> Remove "zh" -> Upload "zh" file "B" - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript file "chinese_transcripts.srt" for "zh" language code - And I see translations for "zh" - Then I remove translation for "zh" language code - And I upload transcript file "uk_transcripts.srt" for "zh" language code - And I save changes - Then when I view the video it does show the captions - And I see "Привіт, edX вітає вас." text in the captions - - # 17 - Scenario: User cannot select the same language twice - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I click button "Add" - And I choose "zh" language code - And I click button "Add" - Then I cannot choose "zh" language code - - # 18 - Scenario: User can see table of content at the first position - Given I have created a Video component - And I edit the component - And I open tab "Advanced" - And I upload transcript files: - |lang_code|filename | - |uk |uk_transcripts.srt | - |table |chinese_transcripts.srt| - And I save changes - Then when I view the video it does show the captions - And I see "好 各位同学" text in the captions - And video language menu has "table, uk" translations - And I see video language with code "table" at position "0" - diff --git a/common/test/acceptance/pages/lms/video/video.py b/common/test/acceptance/pages/lms/video/video.py index 1f69e1125b..dd05e2ca6b 100644 --- a/common/test/acceptance/pages/lms/video/video.py +++ b/common/test/acceptance/pages/lms/video/video.py @@ -301,9 +301,7 @@ class VideoPage(PageObject): str: Captions Text. """ - # wait until captions rendered completely - captions_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['captions_rendered']) - self.wait_for_element_presence(captions_rendered_selector, 'Captions Rendered') + self.wait_for_captions() captions_selector = self.get_element_selector(CSS_CLASS_NAMES['captions_text']) subs = self.q(css=captions_selector).html @@ -535,9 +533,7 @@ class VideoPage(PageObject): captions_selector = self.get_element_selector(CSS_CLASS_NAMES['captions']) EmptyPromise(lambda: self.q(css=captions_selector).visible, 'Subtitles Visible').fulfill() - # wait until captions rendered completely - captions_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['captions_rendered']) - self.wait_for_element_presence(captions_rendered_selector, 'Captions Rendered') + self.wait_for_captions() return True @@ -799,3 +795,10 @@ class VideoPage(PageObject): classes = self.q(css=selector).attrs('class')[0].split() return 'active' in classes + + def wait_for_captions(self): + """ + Wait until captions rendered completely. + """ + captions_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['captions_rendered']) + self.wait_for_element_presence(captions_rendered_selector, 'Captions Rendered') diff --git a/common/test/acceptance/pages/studio/video/video.py b/common/test/acceptance/pages/studio/video/video.py index 43e6729cf7..462d4d7011 100644 --- a/common/test/acceptance/pages/studio/video/video.py +++ b/common/test/acceptance/pages/studio/video/video.py @@ -17,7 +17,7 @@ CLASS_SELECTORS = { 'video_xmodule': '.xmodule_VideoModule', 'video_spinner': '.video-wrapper .spinner', 'video_controls': 'section.video-controls', - 'attach_handout': '.upload-dialog > input[type="file"]', + 'attach_asset': '.upload-dialog > input[type="file"]', 'upload_dialog': '.wrapper-modal-window-assetupload', 'xblock': '.add-xblock-component', 'slider_range': '.slider-range', @@ -27,11 +27,38 @@ BUTTON_SELECTORS = { 'create_video': 'a[data-category="video"]', 'handout_download': '.video-handout.video-download-button a', 'handout_download_editor': '.wrapper-comp-setting.file-uploader .download-action', - 'upload_handout': '.upload-action', - 'handout_submit': '.action-upload', + 'upload_asset': '.upload-action', + 'asset_submit': '.action-upload', 'handout_clear': '.wrapper-comp-setting.file-uploader .setting-clear', + 'translations_clear': '.metadata-video-translations .setting-clear', + 'translation_add': '.wrapper-translations-settings > a', } +DISPLAY_NAME = "Component Display Name" + +DEFAULT_SETTINGS = [ + # basic + [DISPLAY_NAME, 'Video', False], + ['Default Video URL', 'http://youtu.be/OEoXaMPEzfM, , ', False], + + # advanced + [DISPLAY_NAME, 'Video', False], + ['Default Timed Transcript', '', False], + ['Download Transcript Allowed', 'False', False], + ['Downloadable Transcript URL', '', False], + ['Show Transcript', 'True', False], + ['Transcript Languages', '', False], + ['Upload Handout', '', False], + ['Video Download Allowed', 'False', False], + ['Video File URLs', '', False], + ['Video Start Time', '00:00:00', False], + ['Video Stop Time', '00:00:00', False], + ['YouTube ID', 'OEoXaMPEzfM', False], + ['YouTube ID for .75x speed', '', False], + ['YouTube ID for 1.25x speed', '', False], + ['YouTube ID for 1.5x speed', '', False] +] + @js_defined('window.Video', 'window.RequireJS.require', 'window.jQuery', 'window.XModule', 'window.XBlock', 'window.MathJax.isReady') @@ -72,18 +99,20 @@ class VideoComponentPage(VideoPage): """ if not YouTubeStubConfig.get_configuration().get('youtube_api_blocked'): self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_init']).present, 'Video Player Initialized') - self._wait_for(lambda: not self.q(css=CLASS_SELECTORS['video_spinner']).visible, 'Video Buffering Completed') + self._wait_for(lambda: not self.q(css=CLASS_SELECTORS['video_spinner']).visible, + 'Video Buffering Completed') self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_controls']).visible, 'Player Controls are Visible') - def click_button(self, button_name): + def click_button(self, button_name, index=0): """ Click on a button as specified by `button_name` Arguments: button_name (str): button name + index (int): query index """ - self.q(css=BUTTON_SELECTORS[button_name]).first.click() + self.q(css=BUTTON_SELECTORS[button_name]).nth(index).click() self.wait_for_ajax() @staticmethod @@ -105,16 +134,30 @@ class VideoComponentPage(VideoPage): handout_filename (str): handout file name """ - handout_path = self.file_path(handout_filename) + self.upload_asset(handout_filename) - self.click_button('upload_handout') + def upload_asset(self, asset_filename, asset_type='handout', index=0): + """ + Upload a asset file to assets - self.q(css=CLASS_SELECTORS['attach_handout']).results[0].send_keys(handout_path) + Arguments: + asset_filename (str): asset file name + asset_type (str): one of `handout`, `transcript` + index (int): query index - self.click_button('handout_submit') + """ + asset_file_path = self.file_path(asset_filename) + self.click_button('upload_asset', index) + self.q(css=CLASS_SELECTORS['attach_asset']).results[0].send_keys(asset_file_path) + self.click_button('asset_submit') + + # Only srt format transcript files can be uploaded, If an error + # occurs due to incorrect transcript file we will return from here + if asset_type == 'transcript' and self.q(css='#upload_error').present: + return # confirm upload completion - self._wait_for(lambda: not self.q(css=CLASS_SELECTORS['upload_dialog']).present, 'Upload Handout Completed') + self._wait_for(lambda: not self.q(css=CLASS_SELECTORS['upload_dialog']).present, 'Upload Completed') def clear_handout(self): """ @@ -127,7 +170,6 @@ class VideoComponentPage(VideoPage): Download handout at `url` """ kwargs = dict() - session_id = [{i['name']: i['value']} for i in self.browser.get_cookies() if i['name'] == u'sessionid'] if session_id: kwargs.update({ @@ -135,6 +177,7 @@ class VideoComponentPage(VideoPage): }) response = requests.get(url, **kwargs) + return response.status_code < 400, response.headers def download_handout(self, mime_type, is_editor=False): @@ -149,7 +192,6 @@ class VideoComponentPage(VideoPage): """ selector = BUTTON_SELECTORS['handout_download_editor'] if is_editor else BUTTON_SELECTORS['handout_download'] - handout_url = self.q(css=selector).attrs('href')[0] result, headers = self._get_handout(handout_url) @@ -164,7 +206,7 @@ class VideoComponentPage(VideoPage): def create_video(self): """ - Create a Video Component by clicking on Video button and wait for rendering to complete. + Create a Video Component by clicking on Video button and wait for rendering completion. """ # Create video self.click_button('create_video') @@ -205,32 +247,228 @@ class VideoComponentPage(VideoPage): return 'focused' in attributes - def set_settings_field_value(self, field, value): + @property + def is_slider_range_visible(self): """ - In Advanced Tab set `field` with `value` + Return True if slider range is visible. + """ + return self.q(css=CLASS_SELECTORS['slider_range']).visible + + def verify_settings(self): + """ + Verify that video component has correct default settings. + """ + query = '.wrapper-comp-setting' + settings = self.q(css=query).results + if len(DEFAULT_SETTINGS) != len(settings): + return False + + for counter, setting in enumerate(settings): + is_verified = self._verify_setting_entry(setting, + DEFAULT_SETTINGS[counter][0], + DEFAULT_SETTINGS[counter][1]) + if is_verified is False: + return is_verified + + return True + + @staticmethod + def _verify_setting_entry(setting, field_name, field_value): + """ + Verify a `setting` entry. Arguments: - field (str): field name - value (str): field value + setting (WebElement): Selenium WebElement + field_name (str): Name of field + field_value (str): Value of field + + Returns: + bool: Does `setting` have correct value. + + """ + if field_name != setting.find_element_by_class_name('setting-label').get_attribute('innerHTML'): + return False + + # Get class attribute values + classes = setting.get_attribute('class').split() + list_type_classes = ['metadata-list-enum', 'metadata-dict', 'metadata-video-translations'] + is_list_type = any(list_type in classes for list_type in list_type_classes) + + if is_list_type: + current_value = ', '.join( + ele.get_attribute('value') for ele in setting.find_elements_by_class_name('list-settings-item')) + elif 'metadata-videolist-enum' in setting.get_attribute('class'): + current_value = ', '.join(item.find_element_by_tag_name('input').get_attribute('value') for item in + setting.find_elements_by_class_name('videolist-settings-item')) + else: + current_value = setting.find_element_by_class_name('setting-input').get_attribute('value') + + if field_value != current_value: + return False + + # Clear button should be visible(active class is present) for + # every setting that don't have 'metadata-videolist-enum' class + if 'metadata-videolist-enum' not in setting.get_attribute('class'): + setting_clear_button = setting.find_elements_by_class_name('setting-clear')[0] + if 'active' not in setting_clear_button.get_attribute('class'): + return False + + return True + + def set_field_value(self, field_name, field_value, field_type='input'): + """ + Set settings input `field` with `value` + + Arguments: + field_name (str): Name of field + field_value (str): Name of value + field_type (str): `input`, `select` etc(more to be added later) """ query = '.wrapper-comp-setting > label:nth-child(1)' field_id = '' - for index, _ in enumerate(self.q(css=query)): - if field in self.q(css=query).nth(index).text[0]: - field_id = self.q(css=query).nth(index).attrs('for')[0] - break + if field_type == 'input': + for index, _ in enumerate(self.q(css=query)): + if field_name in self.q(css=query).nth(index).text[0]: + field_id = self.q(css=query).nth(index).attrs('for')[0] + break - self.q(css='#{}'.format(field_id)).fill(value) + self.q(css='#{}'.format(field_id)).fill(field_value) + elif field_type == 'select': + self.q(css='select[name="{0}"] option[value="{1}"]'.format(field_name, field_value)).first.click() - @property - def is_slider_range_visible(self): + def verify_field_value(self, field_name, field_value): """ - Check if slider range visible. + Get settings value of `field_name` + + Arguments: + field_name (str): Name of field + field_value (str): Name of value Returns: - bool: slider range is visible or not + bool: If `field_name` has `field_value` """ - return self.q(css=CLASS_SELECTORS['slider_range']).visible + setting = self._get_setting_entry(field_name) + return self._verify_setting_entry(setting, field_name, field_value) + + def _get_setting_entry(self, field_name): + """ + Get setting entry of `field_name` + + Arguments: + field_name (str): Name of field + + Returns: + setting (WebElement): Selenium WebElement + + """ + for setting in self.q(css='.wrapper-comp-setting').results: + if setting.find_element_by_class_name('setting-label').get_attribute('innerHTML') == field_name: + return setting + + def translations_count(self): + """ + Get count of translations. + """ + return len(self.q(css='.wrapper-translations-settings .list-settings-item').results) + + def select_translation_language(self, language_code, index=0): + """ + Select translation language as specified by `language_code` + + Arguments: + language_code (str): + index (int): query index + + """ + translations_items = '.wrapper-translations-settings .list-settings-item' + language_selector = translations_items + ' select option[value="{}"]'.format(language_code) + self.q(css=language_selector).nth(index).click() + + def upload_translation(self, transcript_name, language_code): + """ + Upload a translation file. + + Arguments: + transcript_name (str): + language_code (str): + + """ + self.click_button('translation_add') + translations_count = self.translations_count() + self.select_translation_language(language_code, translations_count - 1) + self.upload_asset(transcript_name, asset_type='transcript', index=translations_count - 1) + + def replace_translation(self, old_lang_code, new_lang_code, transcript_name): + """ + Replace a translation. + + Arguments: + old_lang_code (str): + new_lang_code (str): + transcript_name (str): + + """ + language_codes = self.translations() + index = language_codes.index(old_lang_code) + self.select_translation_language(new_lang_code, index) + self.upload_asset(transcript_name, asset_type='transcript', index=index) + + def translations(self): + """ + Extract translations + + Returns: + list: list of translation language codes + + """ + translations_selector = '.metadata-video-translations .remove-setting' + return self.q(css=translations_selector).attrs('data-lang') + + def download_translation(self, language_code, text_to_search): + """ + Download a translation having `language_code` and containing `text_to_search` + + Arguments: + language_code (str): language code + text_to_search (str): text to search in translation + + Returns: + bool: whether download was successful + + """ + mime_type = 'application/x-subrip' + lang_code = '/{}?'.format(language_code) + link = [link for link in self.q(css='.download-action').attrs('href') if lang_code in link] + result, headers, content = self._get_transcript(link[0]) + + return result is True and mime_type in headers['content-type'] and text_to_search in content.decode('utf-8') + + def remove_translation(self, language_code): + """ + Remove a translation having `language_code` + + Arguments: + language_code (str): language code + + """ + self.q(css='.remove-action').filter(lambda el: language_code == el.get_attribute('data-lang')).click() + + @property + def upload_status_message(self): + """ + Get asset upload status message + """ + return self.q(css='#upload_error').text[0] + + def captions_lines(self): + """ + Extract partial caption lines. + + As all the captions lines are exactly same so only getting partial lines will work. + """ + self.wait_for_captions() + selector = '.subtitles > li:nth-child({})' + return ' '.join([self.q(css=selector.format(i)).text[0] for i in range(1, 6)]) diff --git a/common/test/acceptance/tests/video/test_studio_video_editor.py b/common/test/acceptance/tests/video/test_studio_video_editor.py new file mode 100644 index 0000000000..914f793527 --- /dev/null +++ b/common/test/acceptance/tests/video/test_studio_video_editor.py @@ -0,0 +1,490 @@ +# -*- coding: utf-8 -*- + +""" +Acceptance tests for CMS Video Editor. +""" + +from .test_studio_video_module import CMSVideoBaseTest + + +class VideoEditorTest(CMSVideoBaseTest): + """ + CMS Video Editor Test Class + """ + + def setUp(self): + super(VideoEditorTest, self).setUp() + + def _create_video_component(self, subtitles=False): + """ + Create a video component and navigate to unit page + + Arguments: + subtitles (bool): Upload subtitles or not + + """ + if subtitles: + self.assets.append('subs_OEoXaMPEzfM.srt.sjson') + + self.navigate_to_course_unit() + + def test_default_settings(self): + """ + Scenario: User can view Video metadata + Given I have created a Video component + And I edit the component + Then I see the correct video settings and default values + """ + self._create_video_component() + self.edit_component() + self.assertTrue(self.video.verify_settings()) + + def test_modify_video_display_name(self): + """ + Scenario: User can modify Video display name + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + Then I can modify video display name + And my video display name change is persisted on save + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.set_field_value('Component Display Name', 'Transformers') + self.save_unit_settings() + self.edit_component() + self.open_advanced_tab() + self.assertTrue(self.video.verify_field_value('Component Display Name', 'Transformers')) + + def test_hidden_captions(self): + """ + Scenario: Captions are hidden when "transcript display" is false + Given I have created a Video component with subtitles + And I have set "transcript display" to False + Then when I view the video it does not show the captions + """ + self._create_video_component(subtitles=True) + # Prevent cookies from overriding course settings + self.browser.delete_cookie('hide_captions') + self.edit_component() + self.open_advanced_tab() + self.video.set_field_value('Show Transcript', 'False', 'select') + self.save_unit_settings() + self.assertFalse(self.video.is_captions_visible()) + + def test_shown_captions(self): + """ + Scenario: Captions are shown when "transcript display" is true + Given I have created a Video component with subtitles + And I have set "transcript display" to True + Then when I view the video it does show the captions + """ + self._create_video_component(subtitles=True) + # Prevent cookies from overriding course settings + self.browser.delete_cookie('hide_captions') + self.edit_component() + self.open_advanced_tab() + self.video.set_field_value('Show Transcript', 'True', 'select') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + + def test_translations_uploading(self): + """ + Scenario: Translations uploading works correctly + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "chinese_transcripts.srt" for "zh" language code + And I save changes + Then when I view the video it does show the captions + And I see "好 各位同学" text in the captions + And I edit the component + And I open tab "Advanced" + And I see translations for "zh" + And I upload transcript file "uk_transcripts.srt" for "uk" language code + And I save changes + Then when I view the video it does show the captions + And I see "好 各位同学" text in the captions + And video language menu has "uk, zh" translations + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "好 各位同学".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh']) + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + self.assertIn(unicode_text, self.video.captions_text) + self.assertEqual(self.video.caption_languages.keys(), ['zh', 'uk']) + + def test_upload_large_transcript(self): + """ + Scenario: User can upload transcript file with > 1mb size + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "1mb_transcripts.srt" for "uk" language code + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('1mb_transcripts.srt', 'uk') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_lines()) + + def test_translations_download_works_w_saving(self): + """ + Scenario: Translations downloading works correctly w/ preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |zh |chinese_transcripts.srt| + And I save changes + And I edit the component + And I open tab "Advanced" + And I see translations for "uk, zh" + And video language menu has "uk, zh" translations + Then I can download transcript for "zh" language code, that contains text "好 各位同学" + And I can download transcript for "uk" language code, that contains text "Привіт, edX вітає вас." + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.save_unit_settings() + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh', 'uk']) + self.assertEqual(self.video.caption_languages.keys(), ['zh', 'uk']) + zh_unicode_text = "好 各位同学".decode('utf-8') + self.assertTrue(self.video.download_translation('zh', zh_unicode_text)) + uk_unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertTrue(self.video.download_translation('uk', uk_unicode_text)) + + def test_translations_download_works_wo_saving(self): + """ + Scenario: Translations downloading works correctly w/o preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |zh |chinese_transcripts.srt| + Then I can download transcript for "zh" language code, that contains text "好 各位同学" + And I can download transcript for "uk" language code, that contains text "Привіт, edX вітає вас." + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'zh') + zh_unicode_text = "好 各位同学".decode('utf-8') + self.assertTrue(self.video.download_translation('zh', zh_unicode_text)) + uk_unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertTrue(self.video.download_translation('uk', uk_unicode_text)) + + def test_translations_remove_works_w_saving(self): + """ + Scenario: Translations removing works correctly w/ preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |zh |chinese_transcripts.srt| + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + And video language menu has "uk, zh" translations + And I edit the component + And I open tab "Advanced" + And I see translations for "uk, zh" + Then I remove translation for "uk" language code + And I save changes + Then when I view the video it does show the captions + And I see "好 各位同学" text in the captions + And I edit the component + And I open tab "Advanced" + And I see translations for "zh" + Then I remove translation for "zh" language code + And I save changes + Then when I view the video it does not show the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.assertEqual(self.video.caption_languages.keys(), ['zh', 'uk']) + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh', 'uk']) + self.video.remove_translation('uk') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "好 各位同学".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh']) + self.video.remove_translation('zh') + self.save_unit_settings() + self.assertFalse(self.video.is_captions_visible()) + + def test_translations_remove_works_wo_saving(self): + """ + Scenario: Translations removing works correctly w/o preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "uk_transcripts.srt" for "uk" language code + And I see translations for "uk" + Then I remove translation for "uk" language code + And I save changes + Then when I view the video it does not show the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.assertEqual(self.video.translations(), ['uk']) + self.video.remove_translation('uk') + self.save_unit_settings() + self.assertFalse(self.video.is_captions_visible()) + + def test_translations_clearing_works_w_saving(self): + """ + Scenario: Translations clearing works correctly w/ preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |zh |chinese_transcripts.srt| + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + And video language menu has "uk, zh" translations + And I edit the component + And I open tab "Advanced" + And I see translations for "uk, zh" + And I click button "Clear" + And I save changes + Then when I view the video it does not show the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.assertEqual(self.video.caption_languages.keys(), ['zh', 'uk']) + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh', 'uk']) + self.video.click_button('translations_clear') + self.save_unit_settings() + self.assertFalse(self.video.is_captions_visible()) + + def test_translations_clearing_works_wo_saving(self): + """ + Scenario: Translations clearing works correctly w/o preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |zh |chinese_transcripts.srt| + And I click button "Clear" + And I save changes + Then when I view the video it does not show the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.video.click_button('translations_clear') + self.save_unit_settings() + self.assertFalse(self.video.is_captions_visible()) + + def test_cannot_upload_sjson_translation(self): + """ + Scenario: User cannot upload translations in sjson format + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I click button "Add" + And I choose "uk" language code + And I try to upload transcript file "subs_OEoXaMPEzfM.srt.sjson" + Then I see validation error "Only SRT files can be uploaded. Please select a file ending in .srt to upload." + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.click_button('translation_add') + self.video.select_translation_language('uk') + self.video.upload_asset('subs_OEoXaMPEzfM.srt.sjson', asset_type='transcript') + error_msg = 'Only SRT files can be uploaded. Please select a file ending in .srt to upload.' + self.assertEqual(self.video.upload_status_message, error_msg) + + def test_replace_translation_w_save(self): + """ + Scenario: User can easy replace the translation by another one w/ preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "chinese_transcripts.srt" for "zh" language code + And I save changes + Then when I view the video it does show the captions + And I see "好 各位同学" text in the captions + And I edit the component + And I open tab "Advanced" + And I see translations for "zh" + And I replace transcript file for "zh" language code by "uk_transcripts.srt" + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "好 各位同学".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.edit_component() + self.open_advanced_tab() + self.assertEqual(self.video.translations(), ['zh']) + self.video.replace_translation('zh', 'uk', 'uk_transcripts.srt') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + + def test_replace_translation_wo_save(self): + """ + Scenario: User can easy replace the translation by another one w/o preliminary saving + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "chinese_transcripts.srt" for "zh" language code + And I see translations for "zh" + And I replace transcript file for "zh" language code by "uk_transcripts.srt" + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.assertEqual(self.video.translations(), ['zh']) + self.video.replace_translation('zh', 'uk', 'uk_transcripts.srt') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + + def test_translation_upload_remove_upload(self): + """ + Scenario: Upload "zh" file "A" -> Remove "zh" -> Upload "zh" file "B" + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript file "chinese_transcripts.srt" for "zh" language code + And I see translations for "zh" + Then I remove translation for "zh" language code + And I upload transcript file "uk_transcripts.srt" for "zh" language code + And I save changes + Then when I view the video it does show the captions + And I see "Привіт, edX вітає вас." text in the captions + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('chinese_transcripts.srt', 'zh') + self.assertEqual(self.video.translations(), ['zh']) + self.video.remove_translation('zh') + self.video.upload_translation('uk_transcripts.srt', 'zh') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "Привіт, edX вітає вас.".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + + def test_select_language_twice(self): + """ + Scenario: User cannot select the same language twice + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I click button "Add" + And I choose "zh" language code + And I click button "Add" + Then I cannot choose "zh" language code + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.click_button('translation_add') + self.video.select_translation_language('zh') + self.video.click_button('translation_add') + self.video.select_translation_language('zh') + self.assertEqual(self.video.translations(), [u'zh', u'']) + + def test_table_of_contents(self): + """ + Scenario: User can see table of content at the first position + Given I have created a Video component + And I edit the component + And I open tab "Advanced" + And I upload transcript files: + |lang_code|filename | + |uk |uk_transcripts.srt | + |table |chinese_transcripts.srt| + And I save changes + Then when I view the video it does show the captions + And I see "好 各位同学" text in the captions + And video language menu has "table, uk" translations + And I see video language with code "table" at position "0" + """ + self._create_video_component() + self.edit_component() + self.open_advanced_tab() + self.video.upload_translation('uk_transcripts.srt', 'uk') + self.video.upload_translation('chinese_transcripts.srt', 'table') + self.save_unit_settings() + self.assertTrue(self.video.is_captions_visible()) + unicode_text = "好 各位同学".decode('utf-8') + self.assertIn(unicode_text, self.video.captions_text) + self.assertEqual(self.video.caption_languages.keys(), [u'table', u'uk']) + self.assertEqual(self.video.caption_languages.keys()[0], 'table') diff --git a/common/test/acceptance/tests/video/test_studio_video_module.py b/common/test/acceptance/tests/video/test_studio_video_module.py index e7515b1f2c..34220e5bd4 100644 --- a/common/test/acceptance/tests/video/test_studio_video_module.py +++ b/common/test/acceptance/tests/video/test_studio_video_module.py @@ -3,7 +3,7 @@ """ Acceptance tests for CMS Video Module. """ - +from nose.plugins.attrib import attr from unittest import skipIf from ...pages.studio.auto_auth import AutoAuthPage from ...pages.studio.overview import CourseOutlinePage @@ -12,6 +12,7 @@ from ...fixtures.course import CourseFixture, XBlockFixtureDesc from ..helpers import UniqueCourseTest, is_youtube_available, YouTubeStubConfig +@attr('shard_2') @skipIf(is_youtube_available() is False, 'YouTube is not available!') class CMSVideoBaseTest(UniqueCourseTest): """ @@ -281,9 +282,9 @@ class CMSVideoTest(CMSVideoBaseTest): self.open_advanced_tab() - self.video.set_settings_field_value('Video Start Time', '00:00:12') + self.video.set_field_value('Video Start Time', '00:00:12') - self.video.set_settings_field_value('Video Stop Time', '00:00:24') + self.video.set_field_value('Video Stop Time', '00:00:24') self.save_unit_settings() diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py index 635c8b57d3..d73aca1f24 100644 --- a/common/test/acceptance/tests/video/test_video_module.py +++ b/common/test/acceptance/tests/video/test_video_module.py @@ -3,7 +3,7 @@ """ Acceptance tests for Video. """ - +from nose.plugins.attrib import attr from unittest import skipIf, skip from ..helpers import UniqueCourseTest, is_youtube_available, YouTubeStubConfig from ...pages.lms.video.video import VideoPage @@ -28,6 +28,7 @@ HTML5_SOURCES_INCORRECT = [ ] +@attr('shard_2') @skipIf(is_youtube_available() is False, 'YouTube is not available!') class VideoBaseTest(UniqueCourseTest): """