Adding closed captions (not draggable)
This commit is contained in:
@@ -16,6 +16,7 @@ log = logging.getLogger('VideoPage')
|
||||
VIDEO_BUTTONS = {
|
||||
'transcript': '.lang',
|
||||
'transcript_button': '.toggle-transcript',
|
||||
'cc_button': '.toggle-captions',
|
||||
'volume': '.volume',
|
||||
'play': '.video_control.play',
|
||||
'pause': '.video_control.pause',
|
||||
@@ -28,10 +29,12 @@ VIDEO_BUTTONS = {
|
||||
}
|
||||
|
||||
CSS_CLASS_NAMES = {
|
||||
'closed_captions': '.video.closed',
|
||||
'captions_closed': '.video.closed',
|
||||
'captions_rendered': '.video.is-captions-rendered',
|
||||
'captions': '.subtitles',
|
||||
'captions_text': '.subtitles > li',
|
||||
'captions_text': '.subtitles li',
|
||||
'captions_text_getter': '.subtitles li[role="link"][data-index="1"]',
|
||||
'closed_captions': '.closed-captions',
|
||||
'error_message': '.video .video-player h3',
|
||||
'video_container': '.video',
|
||||
'video_sources': '.video-player video source',
|
||||
@@ -293,6 +296,18 @@ class VideoPage(PageObject):
|
||||
"""
|
||||
self._captions_visibility(False)
|
||||
|
||||
def show_closed_captions(self):
|
||||
"""
|
||||
Make closed captions visible.
|
||||
"""
|
||||
self._closed_captions_visibility(True)
|
||||
|
||||
def hide_closed_captions(self):
|
||||
"""
|
||||
Make closed captions invisible.
|
||||
"""
|
||||
self._closed_captions_visibility(False)
|
||||
|
||||
def is_captions_visible(self):
|
||||
"""
|
||||
Get current visibility sate of captions.
|
||||
@@ -302,8 +317,20 @@ class VideoPage(PageObject):
|
||||
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
|
||||
return not self.q(css=caption_state_selector).present
|
||||
caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['captions'])
|
||||
return self.q(css=caption_state_selector).visible
|
||||
|
||||
def is_closed_captions_visible(self):
|
||||
"""
|
||||
Get current visibility sate of closed captions.
|
||||
|
||||
Returns:
|
||||
bool: True means captions are visible, False means captions are not visible
|
||||
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
closed_caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
|
||||
return self.q(css=closed_caption_state_selector).visible
|
||||
|
||||
@wait_for_js
|
||||
def _captions_visibility(self, captions_new_state):
|
||||
@@ -327,7 +354,24 @@ class VideoPage(PageObject):
|
||||
|
||||
# Verify that captions state is toggled/changed
|
||||
EmptyPromise(lambda: self.is_captions_visible() == captions_new_state,
|
||||
"Captions are {state}".format(state=state)).fulfill()
|
||||
"Transcripts are {state}".format(state=state)).fulfill()
|
||||
|
||||
@wait_for_js
|
||||
def _closed_captions_visibility(self, closed_captions_new_state):
|
||||
"""
|
||||
Set the video closed captioning visibility state.
|
||||
|
||||
Arguments:
|
||||
closed_captions_new_state (bool): True means show closed captioning
|
||||
"""
|
||||
states = {True: 'shown', False: 'hidden'}
|
||||
state = states[closed_captions_new_state]
|
||||
|
||||
self.click_player_button('cc_button')
|
||||
|
||||
# Make sure that the captions are visible
|
||||
EmptyPromise(lambda: self.is_closed_captions_visible() == closed_captions_new_state,
|
||||
"Closed captions are {state}".format(state=state)).fulfill()
|
||||
|
||||
@property
|
||||
def captions_text(self):
|
||||
@@ -345,6 +389,31 @@ class VideoPage(PageObject):
|
||||
|
||||
return ' '.join(subs)
|
||||
|
||||
@property
|
||||
def closed_captions_text(self):
|
||||
"""
|
||||
Extract closed captioning text.
|
||||
|
||||
Returns:
|
||||
str: closed captions Text.
|
||||
|
||||
"""
|
||||
self.wait_for_closed_captions()
|
||||
|
||||
closed_captions_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
|
||||
subs = self.q(css=closed_captions_selector).html
|
||||
|
||||
return ' '.join(subs)
|
||||
|
||||
def click_first_line_in_transcript(self):
|
||||
"""
|
||||
Clicks a line in the transcript updating the current caption.
|
||||
"""
|
||||
|
||||
self.wait_for_captions()
|
||||
captions_selector = self.q(css=CSS_CLASS_NAMES['captions_text_getter'])
|
||||
captions_selector.click()
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
"""
|
||||
@@ -494,6 +563,12 @@ class VideoPage(PageObject):
|
||||
response = requests.get(url, **kwargs)
|
||||
return response.status_code < 400, response.headers, response.content
|
||||
|
||||
def get_cookie(self, cookie_name):
|
||||
"""
|
||||
Searches for and returns `cookie_name`
|
||||
"""
|
||||
return self.browser.get_cookie(cookie_name)
|
||||
|
||||
def downloaded_transcript_contains_text(self, transcript_format, text_to_search):
|
||||
"""
|
||||
Download the transcript in format `transcript_format` and check that it contains the text `text_to_search`
|
||||
@@ -837,6 +912,20 @@ class VideoPage(PageObject):
|
||||
captions_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['captions_rendered'])
|
||||
self.wait_for_element_presence(captions_rendered_selector, 'Captions Rendered')
|
||||
|
||||
def wait_for_closed_captions(self):
|
||||
"""
|
||||
Wait until closed captions are rendered completely.
|
||||
"""
|
||||
cc_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
|
||||
self.wait_for_element_visibility(cc_rendered_selector, 'Closed captions rendered')
|
||||
|
||||
def wait_for_closed_captions_to_be_hidden(self):
|
||||
"""
|
||||
Waits for the closed captions to be turned off completely.
|
||||
"""
|
||||
cc_rendered_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
|
||||
self.wait_for_element_invisibility(cc_rendered_selector, 'Closed captions hidden')
|
||||
|
||||
|
||||
def _parse_time_str(time_str):
|
||||
"""
|
||||
|
||||
@@ -13,11 +13,11 @@ from selenium.webdriver.common.keys import Keys
|
||||
|
||||
|
||||
CLASS_SELECTORS = {
|
||||
'video_container': 'div.video',
|
||||
'video_container': '.video',
|
||||
'video_init': '.is-initialized',
|
||||
'video_xmodule': '.xmodule_VideoModule',
|
||||
'video_spinner': '.video-wrapper .spinner',
|
||||
'video_controls': 'section.video-controls',
|
||||
'video_controls': '.video-controls',
|
||||
'attach_asset': '.upload-dialog > input[type="file"]',
|
||||
'upload_dialog': '.wrapper-modal-window-assetupload',
|
||||
'xblock': '.add-xblock-component',
|
||||
@@ -264,7 +264,7 @@ class VideoComponentPage(VideoPage):
|
||||
line_number (int): caption line number
|
||||
|
||||
"""
|
||||
caption_line_selector = ".subtitles > li[data-index='{index}']".format(index=line_number - 1)
|
||||
caption_line_selector = ".subtitles li[data-index='{index}']".format(index=line_number - 1)
|
||||
self.q(css=caption_line_selector).results[0].send_keys(Keys.ENTER)
|
||||
|
||||
def is_caption_line_focused(self, line_number):
|
||||
@@ -275,7 +275,7 @@ class VideoComponentPage(VideoPage):
|
||||
line_number (int): caption line number
|
||||
|
||||
"""
|
||||
caption_line_selector = ".subtitles > li[data-index='{index}']".format(index=line_number - 1)
|
||||
caption_line_selector = ".subtitles li[data-index='{index}']".format(index=line_number - 1)
|
||||
attributes = self.q(css=caption_line_selector).attrs('class')
|
||||
|
||||
return 'focused' in attributes
|
||||
@@ -504,7 +504,7 @@ class VideoComponentPage(VideoPage):
|
||||
As all the captions lines are exactly same so only getting partial lines will work.
|
||||
"""
|
||||
self.wait_for_captions()
|
||||
selector = '.subtitles > li:nth-child({})'
|
||||
selector = '.subtitles li:nth-child({})'
|
||||
return ' '.join([self.q(css=selector.format(i)).text[0] for i in range(1, 6)])
|
||||
|
||||
def set_url_field(self, url, field_number):
|
||||
|
||||
@@ -142,7 +142,7 @@ class VideoEditorTest(CMSVideoBaseTest):
|
||||
self.open_advanced_tab()
|
||||
self.video.upload_translation('1mb_transcripts.srt', 'uk')
|
||||
self.save_unit_settings()
|
||||
self.assertTrue(self.video.is_captions_visible())
|
||||
self.video.wait_for(self.video.is_captions_visible, 'Captions are visible', timeout=10)
|
||||
unicode_text = "Привіт, edX вітає вас.".decode('utf-8')
|
||||
self.assertIn(unicode_text, self.video.captions_lines())
|
||||
|
||||
|
||||
@@ -255,7 +255,6 @@ class CMSVideoTest(CMSVideoBaseTest):
|
||||
Then when I view the video it does show the captions
|
||||
"""
|
||||
self._create_course_unit(subtitles=True)
|
||||
|
||||
self.assertTrue(self.video.is_captions_visible())
|
||||
|
||||
def test_captions_toggling(self):
|
||||
|
||||
@@ -212,9 +212,9 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
# Verify that video has rendered in "Youtube" mode
|
||||
self.assertTrue(self.video.is_video_rendered('youtube'))
|
||||
|
||||
def test_cc_button_wo_english_transcript(self):
|
||||
def test_transcript_button_wo_english_transcript(self):
|
||||
"""
|
||||
Scenario: CC button works correctly w/o english transcript in Youtube mode
|
||||
Scenario: Transcript button works correctly w/o english transcript in Youtube mode
|
||||
Given the course has a Video component in "Youtube" mode
|
||||
And I have defined a non-english transcript for the video
|
||||
And I have uploaded a non-english transcript file to assets
|
||||
@@ -226,13 +226,38 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
self.navigate_to_video()
|
||||
self.video.show_captions()
|
||||
|
||||
# Verify that we see "好 各位同学" text in the captions
|
||||
# Verify that we see "好 各位同学" text in the transcript
|
||||
unicode_text = "好 各位同学".decode('utf-8')
|
||||
self.assertIn(unicode_text, self.video.captions_text)
|
||||
|
||||
def test_cc_button_transcripts_and_sub_fields_empty(self):
|
||||
def test_cc_button(self):
|
||||
"""
|
||||
Scenario: CC button works correctly if transcripts and sub fields are empty,
|
||||
Scenario: CC button works correctly with transcript in YouTube mode
|
||||
Given the course has a video component in "Youtube" mode
|
||||
And I have defined a transcript for the video
|
||||
Then I see the closed captioning element over the video
|
||||
"""
|
||||
data = {'transcripts': {'zh': 'chinese_transcripts.srt'}}
|
||||
self.metadata = self.metadata_for_mode('youtube', data)
|
||||
self.assets.append('chinese_transcripts.srt')
|
||||
self.navigate_to_video()
|
||||
|
||||
# Show captions and make sure they're visible and cookie is set
|
||||
self.video.show_closed_captions()
|
||||
self.video.wait_for_closed_captions()
|
||||
self.assertTrue(self.video.is_closed_captions_visible)
|
||||
self.video.reload_page()
|
||||
self.assertTrue(self.video.is_closed_captions_visible)
|
||||
|
||||
# Hide captions and make sure they're hidden and cookie is unset
|
||||
self.video.hide_closed_captions()
|
||||
self.video.wait_for_closed_captions_to_be_hidden()
|
||||
self.video.reload_page()
|
||||
self.video.wait_for_closed_captions_to_be_hidden()
|
||||
|
||||
def test_transcript_button_transcripts_and_sub_fields_empty(self):
|
||||
"""
|
||||
Scenario: Transcript button works correctly if transcripts and sub fields are empty,
|
||||
but transcript file exists in assets (Youtube mode of Video component)
|
||||
Given the course has a Video component in "Youtube" mode
|
||||
And I have uploaded a .srt.sjson file to assets
|
||||
@@ -247,11 +272,11 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
# Verify that we see "Welcome to edX." text in the captions
|
||||
self.assertIn('Welcome to edX.', self.video.captions_text)
|
||||
|
||||
def test_cc_button_hidden_no_translations(self):
|
||||
def test_transcript_button_hidden_no_translations(self):
|
||||
"""
|
||||
Scenario: CC button is hidden if no translations
|
||||
Scenario: Transcript button is hidden if no translations
|
||||
Given the course has a Video component in "Youtube" mode
|
||||
Then the "CC" button is hidden
|
||||
Then the "Transcript" button is hidden
|
||||
"""
|
||||
self.navigate_to_video()
|
||||
self.assertFalse(self.video.is_button_shown('transcript_button'))
|
||||
@@ -522,6 +547,16 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
timeout=5
|
||||
)
|
||||
|
||||
def _verify_closed_caption_text(self, text):
|
||||
"""
|
||||
Scenario: returns True if the captions are visible, False is else
|
||||
"""
|
||||
self.video.wait_for(
|
||||
lambda: (text in self.video.closed_captions_text),
|
||||
u'Closed captions contain "{}" text'.format(text),
|
||||
timeout=5
|
||||
)
|
||||
|
||||
def test_video_language_menu_working(self):
|
||||
"""
|
||||
Scenario: Language menu works correctly in Video component
|
||||
@@ -554,6 +589,43 @@ class YouTubeVideoTest(VideoBaseTest):
|
||||
self.video.select_language('en')
|
||||
self._verify_caption_text('Welcome to edX.')
|
||||
|
||||
def test_video_language_menu_working_closed_captions(self):
|
||||
"""
|
||||
Scenario: Language menu works correctly in Video component, checks closed captions
|
||||
Given the course has a Video component in "Youtube" mode
|
||||
And I have defined multiple language transcripts for the videos
|
||||
And I make sure captions are closed
|
||||
And I see video menu "language" with correct items
|
||||
And I select language with code "en"
|
||||
Then I see "Welcome to edX." text in the closed captions
|
||||
And I select language with code "zh"
|
||||
Then I see "我们今天要讲的题目是" text in the closed captions
|
||||
"""
|
||||
self.assets.extend(['chinese_transcripts.srt', 'subs_3_yD_cEKoCk.srt.sjson'])
|
||||
data = {'transcripts': {"zh": "chinese_transcripts.srt"}, 'sub': '3_yD_cEKoCk'}
|
||||
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
|
||||
|
||||
# go to video
|
||||
self.navigate_to_video()
|
||||
self.video.show_closed_captions()
|
||||
|
||||
correct_languages = {'en': 'English', 'zh': 'Chinese'}
|
||||
self.assertEqual(self.video.caption_languages, correct_languages)
|
||||
|
||||
# we start the video, then pause it to activate the transcript
|
||||
self.video.click_player_button('play')
|
||||
self.video.wait_for_position('0:01')
|
||||
self.video.click_player_button('pause')
|
||||
|
||||
self.video.select_language('en')
|
||||
self.video.click_first_line_in_transcript()
|
||||
self._verify_closed_caption_text('Welcome to edX.')
|
||||
|
||||
self.video.select_language('zh')
|
||||
unicode_text = "我们今天要讲的题目是".decode('utf-8')
|
||||
self.video.click_first_line_in_transcript()
|
||||
self._verify_closed_caption_text(unicode_text)
|
||||
|
||||
def test_multiple_videos_in_sequentials_load_and_work(self):
|
||||
"""
|
||||
Scenario: Multiple videos in sequentials all load and work, switching between sequentials
|
||||
|
||||
Reference in New Issue
Block a user