Files
edx-platform/common/test/acceptance/tests/video/test_video_module.py
2021-03-09 18:03:34 +05:00

247 lines
8.4 KiB
Python

"""
Acceptance tests for Video.
"""
import os
from unittest import skipIf
from unittest.mock import patch
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
from common.test.acceptance.pages.lms.courseware import CoursewarePage
from common.test.acceptance.pages.lms.tab_nav import TabNavPage
from common.test.acceptance.pages.lms.video.video import VideoPage
from common.test.acceptance.tests.helpers import (
UniqueCourseTest,
YouTubeStubConfig,
is_youtube_available,
)
from openedx.core.lib.tests import attr
VIDEO_SOURCE_PORT = 8777
VIDEO_HOSTNAME = os.environ.get('BOK_CHOY_HOSTNAME', 'localhost')
HTML5_SOURCES = [
f'http://{VIDEO_HOSTNAME}:{VIDEO_SOURCE_PORT}/gizmo.mp4',
f'http://{VIDEO_HOSTNAME}:{VIDEO_SOURCE_PORT}/gizmo.webm',
f'http://{VIDEO_HOSTNAME}:{VIDEO_SOURCE_PORT}/gizmo.ogv',
]
HTML5_SOURCES_INCORRECT = [
f'http://{VIDEO_HOSTNAME}:{VIDEO_SOURCE_PORT}/gizmo.mp99',
]
HLS_SOURCES = [
f'http://{VIDEO_HOSTNAME}:{VIDEO_SOURCE_PORT}/hls/history.m3u8',
]
@skipIf(is_youtube_available() is False, 'YouTube is not available!')
class VideoBaseTest(UniqueCourseTest):
"""
Base class for tests of the Video Player
Sets up the course and provides helper functions for the Video tests.
"""
def setUp(self):
"""
Initialization of pages and course fixture for video tests
"""
super().setUp()
self.longMessage = True
self.video = VideoPage(self.browser)
self.tab_nav = TabNavPage(self.browser)
self.courseware_page = CoursewarePage(self.browser, self.course_id)
self.auth_page = AutoAuthPage(self.browser, course_id=self.course_id)
self.course_fixture = CourseFixture(
self.course_info['org'], self.course_info['number'],
self.course_info['run'], self.course_info['display_name']
)
self.metadata = None
self.assets = []
self.contents_of_verticals = None
self.youtube_configuration = {}
self.user_info = {}
# reset youtube stub server
self.addCleanup(YouTubeStubConfig.reset)
def navigate_to_video(self):
""" Prepare the course and get to the video and render it """
self._install_course_fixture()
self._navigate_to_courseware_video_and_render()
def navigate_to_video_no_render(self):
"""
Prepare the course and get to the video unit
however do not wait for it to render, because
the has been an error.
"""
self._install_course_fixture()
self._navigate_to_courseware_video_no_render()
def _install_course_fixture(self):
""" Install the course fixture that has been defined """
if self.assets:
self.course_fixture.add_asset(self.assets)
chapter_sequential = XBlockFixtureDesc('sequential', 'Test Section')
chapter_sequential.add_children(*self._add_course_verticals())
chapter = XBlockFixtureDesc('chapter', 'Test Chapter').add_children(chapter_sequential)
self.course_fixture.add_children(chapter)
self.course_fixture.install()
if len(self.youtube_configuration) > 0:
YouTubeStubConfig.configure(self.youtube_configuration)
def _add_course_verticals(self):
"""
Create XBlockFixtureDesc verticals
:return: a list of XBlockFixtureDesc
"""
xblock_verticals = []
_contents_of_verticals = self.contents_of_verticals
# Video tests require at least one vertical with a single video.
if not _contents_of_verticals:
_contents_of_verticals = [[{'display_name': 'Video', 'metadata': self.metadata}]]
for vertical_index, vertical in enumerate(_contents_of_verticals):
xblock_verticals.append(self._create_single_vertical(vertical, vertical_index))
return xblock_verticals
def _create_single_vertical(self, vertical_contents, vertical_index):
"""
Create a single course vertical of type XBlockFixtureDesc with category `vertical`.
A single course vertical can contain single or multiple video modules.
:param vertical_contents: a list of items for the vertical to contain
:param vertical_index: index for the vertical display name
:return: XBlockFixtureDesc
"""
xblock_course_vertical = XBlockFixtureDesc('vertical', f'Test Vertical-{vertical_index}')
for video in vertical_contents:
xblock_course_vertical.add_children(
XBlockFixtureDesc('video', video['display_name'], metadata=video.get('metadata')))
return xblock_course_vertical
def _navigate_to_courseware_video(self):
""" Register for the course and navigate to the video unit """
self.auth_page.visit()
self.user_info = self.auth_page.user_info
self.courseware_page.visit()
def _navigate_to_courseware_video_and_render(self):
""" Wait for the video player to render """
self._navigate_to_courseware_video()
self.video.wait_for_video_player_render()
def _navigate_to_courseware_video_no_render(self):
""" Wait for the video Xmodule but not for rendering """
self._navigate_to_courseware_video()
self.video.wait_for_video_class()
def metadata_for_mode(self, player_mode, additional_data=None):
"""
Create a dictionary for video player configuration according to `player_mode`
:param player_mode (str): Video player mode
:param additional_data (dict): Optional additional metadata.
:return: dict
"""
metadata = {}
youtube_ids = {
'youtube_id_1_0': '',
'youtube_id_0_75': '',
'youtube_id_1_25': '',
'youtube_id_1_5': '',
}
if player_mode == 'html5':
metadata.update(youtube_ids)
metadata.update({
'html5_sources': HTML5_SOURCES
})
if player_mode == 'youtube_html5':
metadata.update({
'html5_sources': HTML5_SOURCES,
})
if player_mode == 'youtube_html5_unsupported_video':
metadata.update({
'html5_sources': HTML5_SOURCES_INCORRECT
})
if player_mode == 'html5_unsupported_video':
metadata.update(youtube_ids)
metadata.update({
'html5_sources': HTML5_SOURCES_INCORRECT
})
if player_mode == 'hls':
metadata.update(youtube_ids)
metadata.update({
'html5_sources': HLS_SOURCES,
})
if player_mode == 'html5_and_hls':
metadata.update(youtube_ids)
metadata.update({
'html5_sources': HTML5_SOURCES + HLS_SOURCES,
})
if additional_data:
metadata.update(additional_data)
return metadata
def go_to_sequential_position(self, position):
"""
Navigate to sequential specified by `video_display_name`
"""
self.courseware_page.go_to_sequential_position(position)
self.video.wait_for_video_player_render()
@attr('a11y')
class LMSVideoBlockA11yTest(VideoBaseTest):
"""
LMS Video Accessibility Test Class
"""
def setUp(self):
browser = os.environ.get('SELENIUM_BROWSER', 'firefox')
# the a11y tests run in CI under phantomjs which doesn't
# support html5 video or flash player, so the video tests
# don't work in it. We still want to be able to run these
# tests in CI, so override the browser setting if it is
# phantomjs.
if browser == 'phantomjs':
browser = 'firefox'
with patch.dict(os.environ, {'SELENIUM_BROWSER': browser}):
super().setUp()
def test_video_player_a11y(self):
# load transcripts so we can test skipping to
self.assets.extend(['english_single_transcript.srt', 'subs_3_yD_cEKoCk.srt.sjson'])
data = {'transcripts': {"en": "english_single_transcript.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_captions()
# limit the scope of the audit to the video player only.
self.video.a11y_audit.config.set_scope(
include=["div.video"]
)
self.video.a11y_audit.check_for_accessibility_errors()