Commit fb16e013 by muhammad-ammar

Merge pull request #3694 from edx/ammar/bok-choy-video-time-tests

Bok-Choy Video Time Tests
parents 5d03cad7 510d0ae1
......@@ -72,6 +72,7 @@ class VideoPage(PageObject):
promise_desc (str): Description of the Promise, used in log messages.
"""
def _is_element_present():
"""
Check if web-element present in DOM.
......@@ -182,7 +183,6 @@ class VideoPage(PageObject):
return Promise(_is_element_present, 'Video Rendering Failed in {0} mode.'.format(mode)).fulfill()
@property
def is_autoplay_enabled(self, video_display_name=None):
"""
Extract `data-autoplay` attribute to check video autoplay is enabled or disabled.
......@@ -202,7 +202,6 @@ class VideoPage(PageObject):
return True
@property
def is_error_message_shown(self, video_display_name=None):
"""
Checks if video player error message shown.
......@@ -231,7 +230,6 @@ class VideoPage(PageObject):
selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_spinner'])
return self.q(css=selector).visible
@property
def error_message_text(self, video_display_name=None):
"""
Extract video player error message text.
......@@ -318,7 +316,6 @@ class VideoPage(PageObject):
EmptyPromise(lambda: _captions_current_state() == captions_new_state,
"Captions are {state}".format(state=state)).fulfill()
@property
def captions_text(self, video_display_name=None):
"""
Extract captions text.
......@@ -663,3 +660,99 @@ class VideoPage(PageObject):
language_names = self.q(css=languages_selector).attrs('textContent')
return dict(zip(language_codes, language_names))
def position(self, video_display_name=None):
"""
Gets current video slider position.
Arguments:
video_display_name (str or None): Display name of a Video.
Returns:
str: current seek position in format min:sec.
"""
selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_time'])
current_seek_position = self.q(css=selector).text[0]
return current_seek_position.split('/')[0].strip()
def state(self, video_display_name=None):
"""
Extract the current state (play, pause etc) of video.
Arguments:
video_display_name (str or None): Display name of a Video.
Returns:
str: current video state
"""
state_selector = self.get_element_selector(video_display_name, CSS_CLASS_NAMES['video_container'])
current_state = self.q(css=state_selector).attrs('class')[0]
if 'is-playing' in current_state:
return 'playing'
elif 'is-paused' in current_state:
return 'pause'
elif 'is-buffered' in current_state:
return 'buffering'
elif 'is-ended' in current_state:
return 'finished'
def _wait_for(self, check_func, desc, result=False, timeout=200):
"""
Calls the method provided as an argument until the return value is not False.
Arguments:
check_func (callable): Function that accepts no arguments and returns a boolean indicating whether the promise is fulfilled.
desc (str): Description of the Promise, used in log messages.
timeout (float): Maximum number of seconds to wait for the Promise to be satisfied before timing out.
"""
if result:
return Promise(check_func, desc, timeout=timeout).fulfill()
else:
return EmptyPromise(check_func, desc, timeout=timeout).fulfill()
def wait_for_state(self, state, video_display_name=None):
"""
Wait until `state` occurs.
Arguments:
state (str): State we wait for.
video_display_name (str or None): Display name of a Video.
"""
self._wait_for(
lambda: self.state(video_display_name) == state,
'State is {state}'.format(state=state)
)
def _parse_time_str(self, time_str):
"""
Parse a string of the form 1:23 into seconds (int).
Arguments:
time_str (str): seek value
Returns:
int: seek value in seconds
"""
time_obj = time.strptime(time_str, '%M:%S')
return time_obj.tm_min * 60 + time_obj.tm_sec
def seek(self, seek_value, video_display_name=None):
"""
Seek the video to position specified by `seek_value`.
Arguments:
seek_value (str): seek value
video_display_name (str or None): Display name of a Video.
"""
seek_time = self._parse_time_str(seek_value)
seek_selector = self.get_element_selector(video_display_name, ' .video')
js_code = "$('{seek_selector}').data('video-player-state').videoPlayer.onSlideSeek({{time: {seek_time}}})".format(
seek_selector=seek_selector, seek_time=seek_time)
self.browser.execute_script(js_code)
......@@ -14,7 +14,7 @@ from ..pages.lms.tab_nav import TabNavPage
from ..pages.lms.course_nav import CourseNavPage
from ..pages.lms.progress import ProgressPage
from ..pages.lms.dashboard import DashboardPage
from ..pages.lms.video import VideoPage
from ..pages.lms.video.video import VideoPage
from ..pages.xblock.acid import AcidView
from ..fixtures.course import CourseFixture, XBlockFixtureDesc, CourseUpdateDesc
......
......@@ -6,15 +6,16 @@ Acceptance tests for Video.
import json
import requests
from .helpers import UniqueCourseTest
from ..pages.lms.video import VideoPage
from ..pages.lms.tab_nav import TabNavPage
from ..pages.lms.course_nav import CourseNavPage
from ..pages.lms.auto_auth import AutoAuthPage
from ..pages.lms.course_info import CourseInfoPage
from ..fixtures.course import CourseFixture, XBlockFixtureDesc
from ..helpers import UniqueCourseTest
from ...pages.lms.video.video import VideoPage
from ...pages.lms.tab_nav import TabNavPage
from ...pages.lms.course_nav import CourseNavPage
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.course_info import CourseInfoPage
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from box.test.flaky import flaky
VIDEO_SOURCE_PORT = 8777
YOUTUBE_STUB_PORT = 9080
YOUTUBE_STUB_URL = 'http://127.0.0.1:{}/'.format(YOUTUBE_STUB_PORT)
......@@ -263,7 +264,7 @@ class YouTubeVideoTest(VideoBaseTest):
# Verify that we see "好 各位同学" text in the captions
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
def test_cc_button_transcripts_and_sub_fields_empty(self):
"""
......@@ -278,7 +279,7 @@ class YouTubeVideoTest(VideoBaseTest):
self.video.show_captions()
# Verify that we see "Hi, welcome to Edx." text in the captions
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
self.assertIn('Hi, welcome to Edx.', self.video.captions_text())
def test_cc_button_hidden_no_translations(self):
"""
......@@ -342,7 +343,7 @@ class YouTubeVideoTest(VideoBaseTest):
self.navigate_to_video()
# check if "Hi, welcome to Edx." text in the captions
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
self.assertIn('Hi, welcome to Edx.', self.video.captions_text())
# check if we can download transcript in "srt" format that has text "Hi, welcome to Edx."
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.'))
......@@ -352,7 +353,7 @@ class YouTubeVideoTest(VideoBaseTest):
# check if we see "好 各位同学" text in the captions
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
# check if we can download transcript in "srt" format that has text "好 各位同学"
unicode_text = "好 各位同学".decode('utf-8')
......@@ -519,10 +520,10 @@ class YouTubeVideoTest(VideoBaseTest):
self.video.select_language('zh')
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
self.video.select_language('en')
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
self.assertIn('Hi, welcome to Edx.', self.video.captions_text())
class YouTubeHtml5VideoTest(VideoBaseTest):
......@@ -562,7 +563,7 @@ class Html5VideoTest(VideoBaseTest):
self.navigate_to_video()
# Verify that the video has autoplay mode disabled
self.assertFalse(self.video.is_autoplay_enabled)
self.assertFalse(self.video.is_autoplay_enabled())
def test_html5_video_rendering_with_unsupported_sources(self):
"""
......@@ -576,11 +577,11 @@ class Html5VideoTest(VideoBaseTest):
self.navigate_to_video_no_render()
# Verify that error message is shown
self.assertTrue(self.video.is_error_message_shown)
self.assertTrue(self.video.is_error_message_shown())
# Verify that error message has correct text
correct_error_message_text = 'No playable video sources found.'
self.assertIn(correct_error_message_text, self.video.error_message_text)
self.assertIn(correct_error_message_text, self.video.error_message_text())
# Verify that spinner is not shown
self.assertFalse(self.video.is_spinner_shown())
......@@ -603,7 +604,7 @@ class Html5VideoTest(VideoBaseTest):
# check if we see "好 各位同学" text in the captions
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
# check if we can download transcript in "srt" format that has text "好 各位同学"
unicode_text = "好 各位同学".decode('utf-8')
......@@ -628,7 +629,7 @@ class Html5VideoTest(VideoBaseTest):
self.navigate_to_video()
# check if "Hi, welcome to Edx." text in the captions
self.assertIn('Hi, welcome to Edx.', self.video.captions_text)
self.assertIn('Hi, welcome to Edx.', self.video.captions_text())
# check if we can download transcript in "srt" format that has text "Hi, welcome to Edx."
self.assertTrue(self.video.downloaded_transcript_contains_text('srt', 'Hi, welcome to Edx.'))
......@@ -639,7 +640,7 @@ class Html5VideoTest(VideoBaseTest):
# check if we see "好 各位同学" text in the captions
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
#Then I can download transcript in "srt" format that has text "好 各位同学"
unicode_text = "好 各位同学".decode('utf-8')
......@@ -690,7 +691,7 @@ class Html5VideoTest(VideoBaseTest):
self.video.show_captions()
# check if we see "Hi, welcome to Edx." text in the captions
self.assertIn("Hi, welcome to Edx.", self.video.captions_text)
self.assertIn("Hi, welcome to Edx.", self.video.captions_text())
def test_cc_button_wo_english_transcript(self):
"""
......@@ -712,7 +713,7 @@ class Html5VideoTest(VideoBaseTest):
# check if we see "好 各位同学" text in the captions
unicode_text = "好 各位同学".decode('utf-8')
self.assertIn(unicode_text, self.video.captions_text)
self.assertIn(unicode_text, self.video.captions_text())
def test_video_rendering(self):
"""
......
"""
Acceptance tests for Video Times(Start, End and Finish) functionality.
"""
from .test_video_module import VideoBaseTest
class VideoTimesTest(VideoBaseTest):
""" Test Video Player Times """
def setUp(self):
super(VideoTimesTest, self).setUp()
def test_video_start_time(self):
"""
Scenario: Start time works for Youtube video
Given we have a video in "Youtube" mode with start_time set to 00:00:10
And I see video slider at "0:10" position
And I click video button "play"
Then video starts playing at or after start_time(00:00:10)
"""
data = {'start_time': '00:00:10'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.assertEqual(self.video.position(), '0:10')
self.video.click_player_button('play')
self.assertGreaterEqual(int(self.video.position().split(':')[1]), 10)
def test_video_end_time_with_default_start_time(self):
"""
Scenario: End time works for Youtube video if starts playing from beginning.
Given we have a video in "Youtube" mode with end time set to 00:00:02
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "0:02" position
"""
data = {'end_time': '00:00:02'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('pause')
self.assertEqual(self.video.position(), '0:02')
def test_video_end_time_wo_default_start_time(self):
"""
Scenario: End time works for Youtube video if starts playing from between.
Given we have a video in "Youtube" mode with end time set to 00:01:00
And I seek video to "0:55" position
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "1:00" position
"""
data = {'end_time': '00:01:00'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.video.seek('0:55')
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('pause')
self.assertEqual(self.video.position(), '1:00')
def test_video_start_time_and_end_time(self):
"""
Scenario: Start time and end time work together for Youtube video.
Given we a video in "Youtube" mode with start time set to 00:00:10 and end_time set to 00:00:12
And I see video slider at "0:10" position
And I click video button "play"
Then I wait until video stop playing
Then I see video slider at "0:12" position
"""
data = {'start_time': '00:00:10', 'end_time': '00:00:12'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.assertEqual(self.video.position(), '0:10')
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('pause')
self.assertEqual(self.video.position(), '0:12')
def test_video_end_time_and_finish_time(self):
"""
Scenario: Youtube video works after pausing at end time and then plays again from End Time to the end.
Given we have a video in "Youtube" mode with start time set to 00:01:41 and end_time set to 00:01:42
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "1:42" position
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "1:54" position
# NOTE: The above video duration(1:54) is disputed because
# 1. Our Video Player first shows Video Duration equals to 1 minute and 56 sec and then 1 minute and 54 sec
# 2 YouTube first shows duration of 1 minute and 56 seconds and then changes duration to 1 minute and 55 sec
#
# The 1:56 time is the duration from metadata. 1:54 time is the duration reported by the video API once
# the video starts playing. BUT sometime video API gives duration equals 1 minute and 55 second.
"""
data = {'start_time': '00:01:41', 'end_time': '00:01:42'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('pause')
self.assertEqual(self.video.position(), '1:42')
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('finished')
self.assertIn(self.video.position(), ['1:54', '1:55'])
def test_video_end_time_with_seek(self):
"""
Scenario: End Time works for Youtube Video if starts playing before Start Time.
Given we have a video in "Youtube" mode with end-time at 0:32 and start-time at 0:30
And I seek video to "0:28" position
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "0:32" position
"""
data = {'start_time': '00:00:30', 'end_time': '00:00:32'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.video.seek('0:28')
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('pause')
self.assertEqual(self.video.position(), '0:32')
def test_video_finish_time_with_seek(self):
"""
Scenario: Finish Time works for Youtube video.
Given it has a video in "Youtube" mode with end-time at 1:00, the video starts playing from 1:42
And I seek video to "1:42" position
And I click video button "play"
And I wait until video stop playing
Then I see video slider at "1:54" position
# NOTE: The above video duration(1:54) is disputed because
# 1. Our Video Player first shows Video Duration equals to 1 minute and 56 sec and then 1 minute and 54 sec
# 2 YouTube first shows duration of 1 minute and 56 seconds and then changes duration to 1 minute and 55 sec
#
# The 1:56 time is the duration from metadata. 1:54 time is the duration reported by the video API once
# the video starts playing. BUT sometime video API gives duration equals 1 minute and 55 second.
"""
data = {'end_time': '00:01:00'}
self.metadata = self.metadata_for_mode('youtube', additional_data=data)
# go to video
self.navigate_to_video()
self.video.seek('1:42')
self.video.click_player_button('play')
# wait until video stop playing
self.video.wait_for_state('finished')
self.assertIn(self.video.position(), ['1:54', '1:55'])
......@@ -93,92 +93,7 @@ Feature: LMS.Video component
Then the video has rendered in "HTML5" mode
And the video does not show the captions
# Disabling because this test is not reliable and needs to be improved.
# Sometimes by the time it checks the video slider is at 10,
# it is actually at 11, so the test fails.
# 10
# Scenario: Start time works for Youtube video
# Given I am registered for the course "test_course"
# And it has a video in "Youtube" mode:
# | start_time |
# | 00:00:10 |
# And I click video button "play"
# Then I see video slider at "0:10" position
# 4
Scenario: End time works for Youtube video
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:00:02 |
And I click video button "play"
And I wait "5" seconds
Then I see video slider at "0:02" position
# 5
Scenario: Youtube video with end-time at 1:00 and the video starts playing at 0:58
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:01:00 |
And I wait for video controls appear
And I seek video to "0:58" position
And I click video button "play"
And I wait "5" seconds
Then I see video slider at "1:00" position
# 6
Scenario: Start time and end time work together for Youtube video
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:00:10 | 00:00:12 |
And I click video button "play"
Then I see video slider at "0:10" position
And I wait "5" seconds
Then I see video slider at "0:12" position
# 7
Scenario: Youtube video after pausing at end time video plays to the end from end time
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:01:51 | 00:01:52 |
And I click video button "play"
And I wait "5" seconds
# The end time is 00:01:52.
Then I see video slider at "1:52" position
And I click video button "play"
And I wait "8" seconds
# The default video length is 00:01:55.
Then I see video slider at "1:55" position
# 8
Scenario: Youtube video with end-time at 0:32 and start-time at 0:30, the video starts playing from 0:28
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:00:30 | 00:00:32 |
And I wait for video controls appear
And I seek video to "0:28" position
And I click video button "play"
And I wait "8" seconds
Then I see video slider at "0:32" position
# 9
Scenario: Youtube video with end-time at 1:00, the video starts playing from 1:52
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:01:00 |
And I wait for video controls appear
And I seek video to "1:52" position
And I click video button "play"
And I wait "5" seconds
# Video stops at the end.
Then I see video slider at "1:55" position
# 10
@skip_firefox
Scenario: Quality button appears on play
Given the course has a Video component in "Youtube" mode
......@@ -186,7 +101,7 @@ Feature: LMS.Video component
And I click video button "play"
Then I see video button "quality" is visible
# 11
# 5
@skip_firefox
Scenario: Quality button works correctly
Given the course has a Video component in "Youtube" 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