Commit 936bd4d5 by Muhammad Ammar

Bok-Choy CMS Video Tests

parent 619f72f3
...@@ -2,83 +2,7 @@ ...@@ -2,83 +2,7 @@
Feature: CMS Video Component Feature: CMS Video Component
As a course author, I want to be able to view my created videos in Studio As a course author, I want to be able to view my created videos in Studio
# 1
Scenario: YouTube stub server proxies YouTube API correctly
Given youtube stub server proxies YouTube API
And I have created a Video component
Then I can see video button "play"
And I click video button "play"
Then I can see video button "pause"
# 2 # 2
Scenario: YouTube stub server can block YouTube API
Given youtube stub server blocks YouTube API
And I have created a Video component
And I wait for "3" seconds
Then I do not see video button "play"
# 3
Scenario: Autoplay is disabled in Studio
Given I have created a Video component
Then when I view the video it does not have autoplay enabled
# 4
Scenario: Creating a video takes a single click
Given I have clicked the new unit button
Then creating a video takes a single click
# 5
# Sauce Labs cannot delete cookies
@skip_sauce
Scenario: Captions are hidden correctly
Given I have created a Video component with subtitles
And I have hidden captions
Then when I view the video it does not show the captions
# 6
# Sauce Labs cannot delete cookies
@skip_sauce
Scenario: Captions are shown correctly
Given I have created a Video component with subtitles
Then when I view the video it does show the captions
# 7
# Sauce Labs cannot delete cookies
@skip_sauce
Scenario: Captions are toggled correctly
Given I have created a Video component with subtitles
And I have toggled captions
Then when I view the video it does show the captions
# 8
Scenario: Video data is shown correctly
Given I have created a video with only XML data
And I reload the page
Then the correct Youtube video is shown
# 9
# Disabled 11/26 due to flakiness in master.
# Enabled back on 11/29.
Scenario: When enter key is pressed on a caption shows an outline around it
Given I have created a Video component with subtitles
And Make sure captions are opened
Then I focus on caption line with data-index "0"
Then I press "enter" button on caption line with data-index "0"
And I see caption line with data-index "0" has class "focused"
# 10
Scenario: When start and end times are specified, a range on slider is shown
Given I have created a Video component with subtitles
And Make sure captions are closed
And I edit the component
And I open tab "Advanced"
And I set value "00:00:12" to the field "Video Start Time"
And I set value "00:00:24" to the field "Video Stop Time"
And I save changes
And I click video button "play"
Then I see a range on slider
# 11
# Disabled 2/19/14 after intermittent failures in master # Disabled 2/19/14 after intermittent failures in master
#Scenario: Check that position is stored on page refresh, position within start-end range #Scenario: Check that position is stored on page refresh, position within start-end range
# Given I have created a Video component with subtitles # Given I have created a Video component with subtitles
...@@ -96,7 +20,7 @@ Feature: CMS Video Component ...@@ -96,7 +20,7 @@ Feature: CMS Video Component
# And I click video button "play" # And I click video button "play"
# Then I see video starts playing from "0:16" position # Then I see video starts playing from "0:16" position
# 12 # 3
# Disabled 2/18/14 after intermittent failures in master # Disabled 2/18/14 after intermittent failures in master
# Scenario: Check that position is stored on page refresh, position before start-end range # Scenario: Check that position is stored on page refresh, position before start-end range
# Given I have created a Video component with subtitles # Given I have created a Video component with subtitles
...@@ -114,7 +38,7 @@ Feature: CMS Video Component ...@@ -114,7 +38,7 @@ Feature: CMS Video Component
# And I click video button "play" # And I click video button "play"
# Then I see video starts playing from "0:12" position # Then I see video starts playing from "0:12" position
# 13 # 4
# Disabled 2/18/14 after intermittent failures in master # Disabled 2/18/14 after intermittent failures in master
# Scenario: Check that position is stored on page refresh, position after start-end range # Scenario: Check that position is stored on page refresh, position after start-end range
# Given I have created a Video component with subtitles # Given I have created a Video component with subtitles
......
...@@ -55,7 +55,10 @@ class StubYouTubeHandler(StubHttpRequestHandler): ...@@ -55,7 +55,10 @@ class StubYouTubeHandler(StubHttpRequestHandler):
"Youtube provider received GET request to path {}".format(self.path) "Youtube provider received GET request to path {}".format(self.path)
) )
if 'test_transcripts_youtube' in self.path: if 'get_config' in self.path:
self.send_json_response(self.server.config)
elif 'test_transcripts_youtube' in self.path:
if 't__eq_exist' in self.path: if 't__eq_exist' in self.path:
status_message = "".join([ status_message = "".join([
......
...@@ -122,20 +122,24 @@ class VideoPage(PageObject): ...@@ -122,20 +122,24 @@ class VideoPage(PageObject):
else: else:
return '.vert.vert-0' return '.vert.vert-0'
def get_element_selector(self, class_name): def get_element_selector(self, class_name, vertical=True):
""" """
Construct unique element selector. Construct unique element selector.
Arguments: Arguments:
class_name (str): css class name for an element. class_name (str): css class name for an element.
vertical (bool): do we need vertical css selector or not. vertical css selector is not present in Studio
Returns: Returns:
str: Element Selector. str: Element Selector.
""" """
return '{vertical} {video_element}'.format( if vertical:
vertical=self.get_video_vertical_selector(self.current_video_display_name), return '{vertical} {video_element}'.format(
video_element=class_name) vertical=self.get_video_vertical_selector(self.current_video_display_name),
video_element=class_name)
else:
return class_name
def use_video(self, video_display_name): def use_video(self, video_display_name):
""" """
...@@ -253,6 +257,17 @@ class VideoPage(PageObject): ...@@ -253,6 +257,17 @@ class VideoPage(PageObject):
""" """
self._captions_visibility(False) self._captions_visibility(False)
def is_captions_visible(self):
"""
Get current visibility sate of captions.
Returns:
bool: True means captions are visible, False means captions are not visible
"""
caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
return not self.q(css=caption_state_selector).present
@wait_for_js @wait_for_js
def _captions_visibility(self, captions_new_state): def _captions_visibility(self, captions_new_state):
""" """
...@@ -265,28 +280,16 @@ class VideoPage(PageObject): ...@@ -265,28 +280,16 @@ class VideoPage(PageObject):
states = {True: 'Shown', False: 'Hidden'} states = {True: 'Shown', False: 'Hidden'}
state = states[captions_new_state] state = states[captions_new_state]
caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
def _captions_current_state():
"""
Get current visibility sate of captions.
Returns:
bool: True means captions are visible, False means captions are not visible
"""
return not self.q(css=caption_state_selector).present
# Make sure that the CC button is there # Make sure that the CC button is there
EmptyPromise(lambda: self.is_button_shown('CC'), EmptyPromise(lambda: self.is_button_shown('CC'),
"CC button is shown").fulfill() "CC button is shown").fulfill()
# toggle captions visibility state if needed # toggle captions visibility state if needed
if _captions_current_state() != captions_new_state: if self.is_captions_visible() != captions_new_state:
self.click_player_button('CC') self.click_player_button('CC')
# Verify that captions state is toggled/changed # Verify that captions state is toggled/changed
EmptyPromise(lambda: _captions_current_state() == captions_new_state, EmptyPromise(lambda: self.is_captions_visible() == captions_new_state,
"Captions are {state}".format(state=state)).fulfill() "Captions are {state}".format(state=state)).fulfill()
@property @property
......
...@@ -4,20 +4,27 @@ CMS Video ...@@ -4,20 +4,27 @@ CMS Video
import os import os
import requests import requests
from bok_choy.page_object import PageObject
from bok_choy.promise import EmptyPromise, Promise from bok_choy.promise import EmptyPromise, Promise
from bok_choy.javascript import wait_for_js, js_defined from bok_choy.javascript import wait_for_js, js_defined
from ....tests.helpers import YouTubeStubConfig
from ...lms.video.video import VideoPage
from selenium.webdriver.common.keys import Keys
CLASS_SELECTORS = { CLASS_SELECTORS = {
'video_container': 'div.video',
'video_init': '.is-initialized', 'video_init': '.is-initialized',
'video_xmodule': '.xmodule_VideoModule', 'video_xmodule': '.xmodule_VideoModule',
'video_spinner': '.video-wrapper .spinner', 'video_spinner': '.video-wrapper .spinner',
'video_controls': 'section.video-controls', 'video_controls': 'section.video-controls',
'attach_handout': '.upload-dialog > input[type="file"]', 'attach_handout': '.upload-dialog > input[type="file"]',
'upload_dialog': '.wrapper-modal-window-assetupload', 'upload_dialog': '.wrapper-modal-window-assetupload',
'xblock': '.add-xblock-component',
'slider_range': '.slider-range',
} }
BUTTON_SELECTORS = { BUTTON_SELECTORS = {
'create_video': 'a[data-category="video"]',
'handout_download': '.video-handout.video-download-button a', 'handout_download': '.video-handout.video-download-button a',
'handout_download_editor': '.wrapper-comp-setting.file-uploader .download-action', 'handout_download_editor': '.wrapper-comp-setting.file-uploader .download-action',
'upload_handout': '.upload-action', 'upload_handout': '.upload-action',
...@@ -28,7 +35,7 @@ BUTTON_SELECTORS = { ...@@ -28,7 +35,7 @@ BUTTON_SELECTORS = {
@js_defined('window.Video', 'window.RequireJS.require', 'window.jQuery', 'window.XModule', 'window.XBlock', @js_defined('window.Video', 'window.RequireJS.require', 'window.jQuery', 'window.XModule', 'window.XBlock',
'window.MathJax.isReady') 'window.MathJax.isReady')
class VidoComponentPage(PageObject): class VideoComponentPage(VideoPage):
""" """
CMS Video Component Page CMS Video Component Page
""" """
...@@ -37,7 +44,11 @@ class VidoComponentPage(PageObject): ...@@ -37,7 +44,11 @@ class VidoComponentPage(PageObject):
@wait_for_js @wait_for_js
def is_browser_on_page(self): def is_browser_on_page(self):
return self.q(css='div{0}'.format(CLASS_SELECTORS['video_xmodule'])).present return self.q(css='div{0}'.format(CLASS_SELECTORS['video_xmodule'])).present or self.q(
css='div{0}'.format(CLASS_SELECTORS['xblock'])).present
def get_element_selector(self, class_name, vertical=False):
return super(VideoComponentPage, self).get_element_selector(class_name, vertical=vertical)
def _wait_for(self, check_func, desc, result=False, timeout=30): def _wait_for(self, check_func, desc, result=False, timeout=30):
""" """
...@@ -59,9 +70,10 @@ class VidoComponentPage(PageObject): ...@@ -59,9 +70,10 @@ class VidoComponentPage(PageObject):
""" """
Wait until video component rendered completely Wait until video component rendered completely
""" """
self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_init']).present, 'Video Player Initialized') if not YouTubeStubConfig.get_configuration().get('youtube_api_blocked'):
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_init']).present, 'Video Player Initialized')
self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_controls']).visible, 'Player Controls are Visible') 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):
""" """
...@@ -74,6 +86,17 @@ class VidoComponentPage(PageObject): ...@@ -74,6 +86,17 @@ class VidoComponentPage(PageObject):
self.q(css=BUTTON_SELECTORS[button_name]).first.click() self.q(css=BUTTON_SELECTORS[button_name]).first.click()
self.wait_for_ajax() self.wait_for_ajax()
@staticmethod
def file_path(filename):
"""
Construct file path to be uploaded to assets.
Arguments:
filename (str): asset filename
"""
return os.sep.join(__file__.split(os.sep)[:-5]) + '/data/uploads/' + filename
def upload_handout(self, handout_filename): def upload_handout(self, handout_filename):
""" """
Upload a handout file to assets Upload a handout file to assets
...@@ -82,7 +105,7 @@ class VidoComponentPage(PageObject): ...@@ -82,7 +105,7 @@ class VidoComponentPage(PageObject):
handout_filename (str): handout file name handout_filename (str): handout file name
""" """
handout_path = os.sep.join(__file__.split(os.sep)[:-5]) + '/data/uploads/' + handout_filename handout_path = self.file_path(handout_filename)
self.click_button('upload_handout') self.click_button('upload_handout')
...@@ -137,6 +160,77 @@ class VidoComponentPage(PageObject): ...@@ -137,6 +160,77 @@ class VidoComponentPage(PageObject):
""" """
Check if handout download button is visible Check if handout download button is visible
""" """
# TODO! Remove .present below after bok-choy is updated to latest commit, Only .visible is enough return self.q(css=BUTTON_SELECTORS['handout_download']).visible
return self.q(css=BUTTON_SELECTORS['handout_download']).present and self.q(
css=BUTTON_SELECTORS['handout_download']).visible def create_video(self):
"""
Create a Video Component by clicking on Video button and wait for rendering to complete.
"""
# Create video
self.click_button('create_video')
self.wait_for_video_component_render()
def xblocks(self):
"""
Tells the total number of video xblocks present on current unit page.
Returns:
(int): total video xblocks
"""
return len(self.q(css='.xblock-header').filter(
lambda el: 'xblock-header-video' in el.get_attribute('class')).results)
def focus_caption_line(self, line_number):
"""
Focus a caption line as specified by `line_number`
Arguments:
line_number (int): caption line number
"""
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):
"""
Check if a caption line focused
Arguments:
line_number (int): caption line number
"""
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
def set_settings_field_value(self, field, value):
"""
In Advanced Tab set `field` with `value`
Arguments:
field (str): field name
value (str): field value
"""
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
self.q(css='#{}'.format(field_id)).fill(value)
@property
def is_slider_range_visible(self):
"""
Check if slider range visible.
Returns:
bool: slider range is visible or not
"""
return self.q(css=CLASS_SELECTORS['slider_range']).visible
""" """
Test helper functions and base classes. Test helper functions and base classes.
""" """
import json
import unittest import unittest
import functools import functools
import requests import requests
...@@ -194,3 +195,77 @@ class UniqueCourseTest(WebAppTest): ...@@ -194,3 +195,77 @@ class UniqueCourseTest(WebAppTest):
self.course_info['number'], self.course_info['number'],
self.course_info['run'] self.course_info['run']
]) ])
class YouTubeConfigError(Exception):
"""
Error occurred while configuring YouTube Stub Server.
"""
pass
class YouTubeStubConfig(object):
"""
Configure YouTube Stub Server.
"""
PORT = 9080
URL = 'http://127.0.0.1:{}/'.format(PORT)
@classmethod
def configure(cls, config):
"""
Allow callers to configure the stub server using the /set_config URL.
Arguments:
config (dict): Configuration dictionary.
Raises:
YouTubeConfigError
"""
youtube_stub_config_url = cls.URL + 'set_config'
config_data = {param: json.dumps(value) for param, value in config.items()}
response = requests.put(youtube_stub_config_url, data=config_data)
if not response.ok:
raise YouTubeConfigError(
'YouTube Server Configuration Failed. URL {0}, Configuration Data: {1}, Status was {2}'.format(
youtube_stub_config_url, config, response.status_code))
@classmethod
def reset(cls):
"""
Reset YouTube Stub Server Configurations using the /del_config URL.
Raises:
YouTubeConfigError
"""
youtube_stub_config_url = cls.URL + 'del_config'
response = requests.delete(youtube_stub_config_url)
if not response.ok:
raise YouTubeConfigError(
'YouTube Server Configuration Failed. URL: {0} Status was {1}'.format(
youtube_stub_config_url, response.status_code))
@classmethod
def get_configuration(cls):
"""
Allow callers to get current stub server configuration.
Returns:
dict
"""
youtube_stub_config_url = cls.URL + 'get_config'
response = requests.get(youtube_stub_config_url)
if response.ok:
return json.loads(response.content)
else:
return {}
...@@ -7,9 +7,9 @@ Acceptance tests for CMS Video Module. ...@@ -7,9 +7,9 @@ Acceptance tests for CMS Video Module.
from unittest import skipIf from unittest import skipIf
from ...pages.studio.auto_auth import AutoAuthPage from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.studio.overview import CourseOutlinePage from ...pages.studio.overview import CourseOutlinePage
from ...pages.studio.video.video import VidoComponentPage from ...pages.studio.video.video import VideoComponentPage
from ...fixtures.course import CourseFixture, XBlockFixtureDesc from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ..helpers import UniqueCourseTest, is_youtube_available from ..helpers import UniqueCourseTest, is_youtube_available, YouTubeStubConfig
@skipIf(is_youtube_available() is False, 'YouTube is not available!') @skipIf(is_youtube_available() is False, 'YouTube is not available!')
...@@ -24,7 +24,7 @@ class CMSVideoBaseTest(UniqueCourseTest): ...@@ -24,7 +24,7 @@ class CMSVideoBaseTest(UniqueCourseTest):
""" """
super(CMSVideoBaseTest, self).setUp() super(CMSVideoBaseTest, self).setUp()
self.video = VidoComponentPage(self.browser) self.video = VideoComponentPage(self.browser)
# This will be initialized later # This will be initialized later
self.unit_page = None self.unit_page = None
...@@ -41,6 +41,8 @@ class CMSVideoBaseTest(UniqueCourseTest): ...@@ -41,6 +41,8 @@ class CMSVideoBaseTest(UniqueCourseTest):
self.course_info['run'], self.course_info['display_name'] self.course_info['run'], self.course_info['display_name']
) )
self.assets = []
def _install_course_fixture(self): def _install_course_fixture(self):
""" """
Prepare for tests by creating a course with a section, subsection, and unit. Prepare for tests by creating a course with a section, subsection, and unit.
...@@ -49,13 +51,15 @@ class CMSVideoBaseTest(UniqueCourseTest): ...@@ -49,13 +51,15 @@ class CMSVideoBaseTest(UniqueCourseTest):
Create a user and make that user a course author Create a user and make that user a course author
Log the user into studio Log the user into studio
""" """
if self.assets:
self.course_fixture.add_asset(self.assets)
# Create course with Video component # Create course with Video component
self.course_fixture.add_children( self.course_fixture.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc("vertical", "Test Unit").add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('video', 'Video'), XBlockFixtureDesc('video', 'Video')
) )
) )
) )
...@@ -95,17 +99,194 @@ class CMSVideoBaseTest(UniqueCourseTest): ...@@ -95,17 +99,194 @@ class CMSVideoBaseTest(UniqueCourseTest):
""" """
Open component Edit Dialog for first component on page. Open component Edit Dialog for first component on page.
""" """
self.unit_page.xblocks[0].edit() # The 0th entry is the unit page itself.
self.unit_page.xblocks[1].edit()
def open_advanced_tab(self): def open_advanced_tab(self):
""" """
Open components advanced tab. Open components advanced tab.
""" """
self.unit_page.xblocks[0].open_advanced_tab() # The 0th entry is the unit page itself.
self.unit_page.xblocks[1].open_advanced_tab()
def save_unit_settings(self): def save_unit_settings(self):
""" """
Save component settings. Save component settings.
""" """
self.unit_page.xblocks[0].save_settings() # The 0th entry is the unit page itself.
self.unit_page.xblocks[1].save_settings()
class CMSVideoTest(CMSVideoBaseTest):
"""
CMS Video Test Class
"""
def setUp(self):
super(CMSVideoTest, self).setUp()
self.addCleanup(YouTubeStubConfig.reset)
def _create_course_unit(self, youtube_stub_config=None, subtitles=False):
"""
Create a Studio Video Course Unit and Navigate to it.
Arguments:
youtube_stub_config (dict)
subtitles (bool)
"""
if youtube_stub_config:
YouTubeStubConfig.configure(youtube_stub_config)
if subtitles:
self.assets.append('subs_OEoXaMPEzfM.srt.sjson')
self.navigate_to_course_unit()
def _create_video(self):
"""
Create Xblock Video Component.
"""
self.video.create_video()
video_xblocks = self.video.xblocks()
# Total video xblock components count should be equals to 2
# Why 2? One video component is created by default for each test. Please see
# test_studio_video_module.py:CMSVideoTest._create_course_unit
# And we are creating second video component here.
self.assertTrue(video_xblocks == 2)
def test_youtube_stub_proxy(self):
"""
Scenario: YouTube stub server proxies YouTube API correctly
Given youtube stub server proxies YouTube API
And I have created a Video component
Then I can see video button "play"
And I click video button "play"
Then I can see video button "pause"
"""
self._create_course_unit(youtube_stub_config={'youtube_api_blocked': False})
self.assertTrue(self.video.is_button_shown('play'))
self.video.click_player_button('play')
self.assertTrue(self.video.is_button_shown('pause'))
def test_youtube_stub_blocks_youtube_api(self):
"""
Scenario: YouTube stub server can block YouTube API
Given youtube stub server blocks YouTube API
And I have created a Video component
Then I do not see video button "play"
"""
self._create_course_unit(youtube_stub_config={'youtube_api_blocked': True})
self.assertFalse(self.video.is_button_shown('play'))
def test_autoplay_is_disabled(self):
"""
Scenario: Autoplay is disabled in Studio
Given I have created a Video component
Then when I view the video it does not have autoplay enabled
"""
self._create_course_unit()
self.assertFalse(self.video.is_autoplay_enabled)
def test_video_creation_takes_single_click(self):
"""
Scenario: Creating a video takes a single click
And creating a video takes a single click
"""
self._create_course_unit()
# This will create a video by doing a single click and then ensure that video is created
self._create_video()
def test_captions_hidden_correctly(self):
"""
Scenario: Captions are hidden correctly
Given I have created a Video component with subtitles
And I have hidden captions
Then when I view the video it does not show the captions
"""
self._create_course_unit(subtitles=True)
self.video.hide_captions()
self.assertFalse(self.video.is_captions_visible())
def test_captions_shown_correctly(self):
"""
Scenario: Captions are shown correctly
Given I have created a Video component with subtitles
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):
"""
Scenario: Captions are toggled correctly
Given I have created a Video component with subtitles
And I have toggled captions
Then when I view the video it does show the captions
"""
self._create_course_unit(subtitles=True)
self.video.click_player_button('CC')
self.assertFalse(self.video.is_captions_visible())
self.video.click_player_button('CC')
self.assertTrue(self.video.is_captions_visible())
def test_caption_line_focus(self):
"""
Scenario: When enter key is pressed on a caption, an outline shows around it
Given I have created a Video component with subtitles
And Make sure captions are opened
Then I focus on first caption line
And I see first caption line has focused
"""
self._create_course_unit(subtitles=True)
self.video.show_captions()
self.video.focus_caption_line(1)
self.assertTrue(self.video.is_caption_line_focused(1))
def test_slider_range_works(self):
"""
Scenario: When start and end times are specified, a range on slider is shown
Given I have created a Video component with subtitles
And Make sure captions are closed
And I edit the component
And I open tab "Advanced"
And I set value "00:00:12" to the field "Video Start Time"
And I set value "00:00:24" to the field "Video Stop Time"
And I save changes
And I click video button "play"
Then I see a range on slider
"""
self._create_course_unit(subtitles=True)
self.video.hide_captions()
self.edit_component()
self.open_advanced_tab()
self.video.set_settings_field_value('Video Start Time', '00:00:12')
self.video.set_settings_field_value('Video Stop Time', '00:00:24')
self.save_unit_settings()
self.video.click_player_button('play')
self.assertTrue(self.video.is_slider_range_visible)
...@@ -4,10 +4,8 @@ ...@@ -4,10 +4,8 @@
Acceptance tests for Video. Acceptance tests for Video.
""" """
import json
from unittest import skipIf, skip from unittest import skipIf, skip
import requests from ..helpers import UniqueCourseTest, is_youtube_available, YouTubeStubConfig
from ..helpers import UniqueCourseTest, is_youtube_available
from ...pages.lms.video.video import VideoPage from ...pages.lms.video.video import VideoPage
from ...pages.lms.tab_nav import TabNavPage from ...pages.lms.tab_nav import TabNavPage
from ...pages.lms.course_nav import CourseNavPage from ...pages.lms.course_nav import CourseNavPage
...@@ -18,8 +16,6 @@ from ..helpers import skip_if_browser ...@@ -18,8 +16,6 @@ from ..helpers import skip_if_browser
VIDEO_SOURCE_PORT = 8777 VIDEO_SOURCE_PORT = 8777
YOUTUBE_STUB_PORT = 9080
YOUTUBE_STUB_URL = 'http://127.0.0.1:{}/'.format(YOUTUBE_STUB_PORT)
HTML5_SOURCES = [ HTML5_SOURCES = [
'http://localhost:{0}/gizmo.mp4'.format(VIDEO_SOURCE_PORT), 'http://localhost:{0}/gizmo.mp4'.format(VIDEO_SOURCE_PORT),
...@@ -32,13 +28,6 @@ HTML5_SOURCES_INCORRECT = [ ...@@ -32,13 +28,6 @@ HTML5_SOURCES_INCORRECT = [
] ]
class YouTubeConfigError(Exception):
"""
Error occurred while configuring YouTube Stub Server.
"""
pass
@skipIf(is_youtube_available() is False, 'YouTube is not available!') @skipIf(is_youtube_available() is False, 'YouTube is not available!')
class VideoBaseTest(UniqueCourseTest): class VideoBaseTest(UniqueCourseTest):
""" """
...@@ -68,7 +57,7 @@ class VideoBaseTest(UniqueCourseTest): ...@@ -68,7 +57,7 @@ class VideoBaseTest(UniqueCourseTest):
self.youtube_configuration = {} self.youtube_configuration = {}
# reset youtube stub server # reset youtube stub server
self.addCleanup(self._reset_youtube_stub_server) self.addCleanup(YouTubeStubConfig.reset)
def navigate_to_video(self): def navigate_to_video(self):
""" Prepare the course and get to the video and render it """ """ Prepare the course and get to the video and render it """
...@@ -96,7 +85,7 @@ class VideoBaseTest(UniqueCourseTest): ...@@ -96,7 +85,7 @@ class VideoBaseTest(UniqueCourseTest):
self.course_fixture.install() self.course_fixture.install()
if len(self.youtube_configuration) > 0: if len(self.youtube_configuration) > 0:
self._configure_youtube_stub_server(self.youtube_configuration) YouTubeStubConfig.configure(self.youtube_configuration)
def _add_course_verticals(self): def _add_course_verticals(self):
""" """
...@@ -148,39 +137,6 @@ class VideoBaseTest(UniqueCourseTest): ...@@ -148,39 +137,6 @@ class VideoBaseTest(UniqueCourseTest):
self._navigate_to_courseware_video() self._navigate_to_courseware_video()
self.video.wait_for_video_class() self.video.wait_for_video_class()
def _configure_youtube_stub_server(self, config):
"""
Allow callers to configure the stub server using the /set_config URL.
:param config: Configuration dictionary.
The request should have PUT data, such that:
Each PUT parameter is the configuration key.
Each PUT value is a JSON-encoded string value for the configuration.
:raise YouTubeConfigError:
"""
youtube_stub_config_url = YOUTUBE_STUB_URL + 'set_config'
config_data = {param: json.dumps(value) for param, value in config.items()}
response = requests.put(youtube_stub_config_url, data=config_data)
if not response.ok:
raise YouTubeConfigError(
'YouTube Server Configuration Failed. URL {0}, Configuration Data: {1}, Status was {2}'.format(
youtube_stub_config_url, config, response.status_code))
def _reset_youtube_stub_server(self):
"""
Reset YouTube Stub Server Configurations using the /del_config URL.
:raise YouTubeConfigError:
"""
youtube_stub_config_url = YOUTUBE_STUB_URL + 'del_config'
response = requests.delete(youtube_stub_config_url)
if not response.ok:
raise YouTubeConfigError(
'YouTube Server Configuration Failed. URL: {0} Status was {1}'.format(
youtube_stub_config_url, response.status_code))
def metadata_for_mode(self, player_mode, additional_data=None): def metadata_for_mode(self, player_mode, additional_data=None):
""" """
Create a dictionary for video player configuration according to `player_mode` Create a dictionary for video player configuration according to `player_mode`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment