Commit 40d5f1e5 by Anton Stupak

Merge pull request #3195 from edx/anton/force-flash

Force video player in flash mode.
parents da470afc d5555470
...@@ -201,7 +201,8 @@ def upload_file(_step, file_name): ...@@ -201,7 +201,8 @@ def upload_file(_step, file_name):
@step('I see "([^"]*)" text in the captions') @step('I see "([^"]*)" text in the captions')
def check_text_in_the_captions(_step, text): def check_text_in_the_captions(_step, text):
world.wait_for(lambda _: world.css_text('.subtitles'), 30) world.wait_for_present('.video.is-captions-rendered')
world.wait_for(lambda _: world.css_text('.subtitles'), timeout=30)
actual_text = world.css_text('.subtitles') actual_text = world.css_text('.subtitles')
assert (text in actual_text) assert (text in actual_text)
......
...@@ -197,11 +197,15 @@ def find_caption_line_by_data_index(index): ...@@ -197,11 +197,15 @@ def find_caption_line_by_data_index(index):
@step('I focus on caption line with data-index "([^"]*)"$') @step('I focus on caption line with data-index "([^"]*)"$')
def focus_on_caption_line(_step, index): def focus_on_caption_line(_step, index):
world.wait_for_present('.video.is-captions-rendered')
world.wait_for(lambda _: world.css_text('.subtitles'), timeout=30)
find_caption_line_by_data_index(int(index.strip()))._element.send_keys(Keys.TAB) find_caption_line_by_data_index(int(index.strip()))._element.send_keys(Keys.TAB)
@step('I press "enter" button on caption line with data-index "([^"]*)"$') @step('I press "enter" button on caption line with data-index "([^"]*)"$')
def click_on_the_caption(_step, index): def click_on_the_caption(_step, index):
world.wait_for_present('.video.is-captions-rendered')
world.wait_for(lambda _: world.css_text('.subtitles'), timeout=30)
find_caption_line_by_data_index(int(index.strip()))._element.send_keys(Keys.ENTER) find_caption_line_by_data_index(int(index.strip()))._element.send_keys(Keys.ENTER)
...@@ -214,7 +218,6 @@ def caption_line_has_class(_step, index, className): ...@@ -214,7 +218,6 @@ def caption_line_has_class(_step, index, className):
@step('I see a range on slider$') @step('I see a range on slider$')
def see_a_range_slider_with_proper_range(_step): def see_a_range_slider_with_proper_range(_step):
world.wait_for_visible(VIDEO_BUTTONS['pause']) world.wait_for_visible(VIDEO_BUTTONS['pause'])
assert world.css_visible(".slider-range") assert world.css_visible(".slider-range")
......
...@@ -396,6 +396,89 @@ function (Initialize) { ...@@ -396,6 +396,89 @@ function (Initialize) {
}); });
}); });
}); });
describe('setPlayerMode', function () {
beforeEach(function () {
state = {
currentPlayerMode: 'flash',
};
});
it('updates player mode', function () {
var setPlayerMode = Initialize.prototype.setPlayerMode;
setPlayerMode.call(state, 'html5');
expect(state.currentPlayerMode).toBe('html5');
setPlayerMode.call(state, 'flash');
expect(state.currentPlayerMode).toBe('flash');
});
it('sets default mode if passed is not supported', function () {
var setPlayerMode = Initialize.prototype.setPlayerMode;
setPlayerMode.call(state, '77html77');
expect(state.currentPlayerMode).toBe('html5');
});
});
describe('getPlayerMode', function () {
beforeEach(function () {
state = {
currentPlayerMode: 'flash',
};
});
it('returns current player mode', function () {
var getPlayerMode = Initialize.prototype.getPlayerMode,
actual = getPlayerMode.call(state);
expect(actual).toBe(state.currentPlayerMode);
});
});
describe('isFlashMode', function () {
it('returns `true` if player in `flash` mode', function () {
var state = {
getPlayerMode: jasmine.createSpy().andReturn('flash'),
},
isFlashMode = Initialize.prototype.isFlashMode,
actual = isFlashMode.call(state);
expect(actual).toBeTruthy();
});
it('returns `false` if player is not in `flash` mode', function () {
var state = {
getPlayerMode: jasmine.createSpy().andReturn('html5'),
},
isFlashMode = Initialize.prototype.isFlashMode,
actual = isFlashMode.call(state);
expect(actual).toBeFalsy();
});
});
describe('isHtml5Mode', function () {
it('returns `true` if player in `html5` mode', function () {
var state = {
getPlayerMode: jasmine.createSpy().andReturn('html5'),
},
isHtml5Mode = Initialize.prototype.isHtml5Mode,
actual = isHtml5Mode.call(state);
expect(actual).toBeTruthy();
});
it('returns `false` if player is not in `html5` mode', function () {
var state = {
getPlayerMode: jasmine.createSpy().andReturn('flash'),
},
isHtml5Mode = Initialize.prototype.isHtml5Mode,
actual = isHtml5Mode.call(state);
expect(actual).toBeFalsy();
});
});
}); });
}); });
......
...@@ -1070,6 +1070,9 @@ function (VideoPlayer) { ...@@ -1070,6 +1070,9 @@ function (VideoPlayer) {
beforeEach(function () { beforeEach(function () {
state = { state = {
youtubeId: jasmine.createSpy().andReturn('videoId'), youtubeId: jasmine.createSpy().andReturn('videoId'),
isFlashMode: jasmine.createSpy().andReturn(false),
isHtml5Mode: jasmine.createSpy().andReturn(true),
setPlayerMode: jasmine.createSpy(),
videoPlayer: { videoPlayer: {
currentTime: 60, currentTime: 60,
isPlaying: jasmine.createSpy(), isPlaying: jasmine.createSpy(),
...@@ -1083,7 +1086,8 @@ function (VideoPlayer) { ...@@ -1083,7 +1086,8 @@ function (VideoPlayer) {
}); });
it('in Flash mode and video is playing', function () { it('in Flash mode and video is playing', function () {
state.currentPlayerMode = 'flash'; state.isFlashMode.andReturn(true);
state.isHtml5Mode.andReturn(false);
state.videoPlayer.isPlaying.andReturn(true); state.videoPlayer.isPlaying.andReturn(true);
VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75');
expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60);
...@@ -1092,7 +1096,8 @@ function (VideoPlayer) { ...@@ -1092,7 +1096,8 @@ function (VideoPlayer) {
}); });
it('in Flash mode and video not started', function () { it('in Flash mode and video not started', function () {
state.currentPlayerMode = 'flash'; state.isFlashMode.andReturn(true);
state.isHtml5Mode.andReturn(false);
state.videoPlayer.isPlaying.andReturn(false); state.videoPlayer.isPlaying.andReturn(false);
VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75');
expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60);
...@@ -1101,13 +1106,11 @@ function (VideoPlayer) { ...@@ -1101,13 +1106,11 @@ function (VideoPlayer) {
}); });
it('in HTML5 mode', function () { it('in HTML5 mode', function () {
state.currentPlayerMode = 'html5';
VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75');
expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75'); expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75');
}); });
it('Youtube video in FF, with new speed equal 1.0', function () { it('Youtube video in FF, with new speed equal 1.0', function () {
state.currentPlayerMode = 'html5';
state.videoType = 'youtube'; state.videoType = 'youtube';
state.browserIsFirefox = true; state.browserIsFirefox = true;
......
...@@ -10,7 +10,7 @@ function() { ...@@ -10,7 +10,7 @@ function() {
* @param {array} list Array to process. * @param {array} list Array to process.
* @param {function} process Calls this function on each item in the list. * @param {function} process Calls this function on each item in the list.
* @return {array} Returns a Promise object to observe when all actions of a * @return {array} Returns a Promise object to observe when all actions of a
certain type bound to the collection, queued or not, have finished. * certain type bound to the collection, queued or not, have finished.
*/ */
var AsyncProcess = { var AsyncProcess = {
array: function (list, process) { array: function (list, process) {
......
...@@ -63,13 +63,16 @@ function (VideoPlayer, VideoStorage) { ...@@ -63,13 +63,16 @@ function (VideoPlayer, VideoStorage) {
fetchMetadata: fetchMetadata, fetchMetadata: fetchMetadata,
getCurrentLanguage: getCurrentLanguage, getCurrentLanguage: getCurrentLanguage,
getDuration: getDuration, getDuration: getDuration,
getPlayerMode: getPlayerMode,
getVideoMetadata: getVideoMetadata, getVideoMetadata: getVideoMetadata,
initialize: initialize, initialize: initialize,
isHtml5Mode: isHtml5Mode,
isFlashMode: isFlashMode, isFlashMode: isFlashMode,
parseSpeed: parseSpeed, parseSpeed: parseSpeed,
parseVideoSources: parseVideoSources, parseVideoSources: parseVideoSources,
parseYoutubeStreams: parseYoutubeStreams, parseYoutubeStreams: parseYoutubeStreams,
saveState: saveState, saveState: saveState,
setPlayerMode: setPlayerMode,
setSpeed: setSpeed, setSpeed: setSpeed,
trigger: trigger, trigger: trigger,
youtubeId: youtubeId youtubeId: youtubeId
...@@ -250,18 +253,6 @@ function (VideoPlayer, VideoStorage) { ...@@ -250,18 +253,6 @@ function (VideoPlayer, VideoStorage) {
} }
} }
// function _setPlayerMode(state)
// By default we will be forcing HTML5 player mode. Only in the case
// when, after initializtion, we will get one available playback rate,
// we will change to Flash player mode. There is a need to store this
// setting in cookies because otherwise we will have to change from
// HTML5 to Flash on every page load in a browser that doesn't fully
// support HTML5. When we have this setting in cookies, we can select
// the proper mode from the start (not having to change mode later on).
function _setPlayerMode(state) {
state.currentPlayerMode = 'html5';
}
// function _parseYouTubeIDs(state) // function _parseYouTubeIDs(state)
// The function parse YouTube stream ID's. // The function parse YouTube stream ID's.
// @return // @return
...@@ -339,8 +330,7 @@ function (VideoPlayer, VideoStorage) { ...@@ -339,8 +330,7 @@ function (VideoPlayer, VideoStorage) {
function _setConfigurations(state) { function _setConfigurations(state) {
_configureCaptions(state); _configureCaptions(state);
_setPlayerMode(state); state.setPlayerMode(state.config.mode);
// Possible value are: 'visible', 'hiding', and 'invisible'. // Possible value are: 'visible', 'hiding', and 'invisible'.
state.controlState = 'visible'; state.controlState = 'visible';
state.controlHideTimeout = null; state.controlHideTimeout = null;
...@@ -520,7 +510,8 @@ function (VideoPlayer, VideoStorage) { ...@@ -520,7 +510,8 @@ function (VideoPlayer, VideoStorage) {
element: element, element: element,
fadeOutTimeout: 1400, fadeOutTimeout: 1400,
captionsFreezeTime: 10000, captionsFreezeTime: 10000,
availableQualities: ['hd720', 'hd1080', 'highres'] availableQualities: ['hd720', 'hd1080', 'highres'],
mode: $.cookie('edX_video_player_mode')
}); });
if (this.config.endTime < this.config.startTime) { if (this.config.endTime < this.config.startTime) {
...@@ -811,8 +802,46 @@ function (VideoPlayer, VideoStorage) { ...@@ -811,8 +802,46 @@ function (VideoPlayer, VideoStorage) {
} }
} }
/**
* Sets player mode.
*
* @param {string} mode Mode to set for the video player if it is supported.
* Otherwise, `html5` is used by default.
*/
function setPlayerMode(mode) {
var supportedModes = ['html5', 'flash'];
mode = _.contains(supportedModes, mode) ? mode : 'html5';
this.currentPlayerMode = mode;
}
/**
* Returns current player mode.
*
* @return {string} Returns string that describes player mode
*/
function getPlayerMode() {
return this.currentPlayerMode;
}
/**
* Checks if current player mode is Flash.
*
* @return {boolean} Returns `true` if current mode is `flash`, otherwise
* it returns `false`
*/
function isFlashMode() { function isFlashMode() {
return this.currentPlayerMode === 'flash'; return this.getPlayerMode() === 'flash';
}
/**
* Checks if current player mode is Html5.
*
* @return {boolean} Returns `true` if current mode is `html5`, otherwise
* it returns `false`
*/
function isHtml5Mode() {
return this.getPlayerMode() === 'html5';
} }
function getCurrentLanguage() { function getCurrentLanguage() {
......
...@@ -251,7 +251,7 @@ function (HTML5Video, Resizer) { ...@@ -251,7 +251,7 @@ function (HTML5Video, Resizer) {
// Remove from the page current iFrame with HTML5 video. // Remove from the page current iFrame with HTML5 video.
state.videoPlayer.player.destroy(); state.videoPlayer.player.destroy();
state.currentPlayerMode = 'flash'; state.setPlayerMode('flash');
console.log('[Video info]: Changing YouTube player mode to "flash".'); console.log('[Video info]: Changing YouTube player mode to "flash".');
...@@ -334,7 +334,7 @@ function (HTML5Video, Resizer) { ...@@ -334,7 +334,7 @@ function (HTML5Video, Resizer) {
methodName, youtubeId; methodName, youtubeId;
if ( if (
this.currentPlayerMode === 'html5' && this.isHtml5Mode() &&
!( !(
this.browserIsFirefox && this.browserIsFirefox &&
newSpeed === '1.0' && newSpeed === '1.0' &&
...@@ -554,7 +554,7 @@ function (HTML5Video, Resizer) { ...@@ -554,7 +554,7 @@ function (HTML5Video, Resizer) {
// For more information, please see the PR that introduced this change: // For more information, please see the PR that introduced this change:
// https://github.com/edx/edx-platform/pull/2841 // https://github.com/edx/edx-platform/pull/2841
if ( if (
(this.currentPlayerMode === 'html5' || availablePlaybackRates.length > 1) && (this.isHtml5Mode() || availablePlaybackRates.length > 1) &&
this.videoType === 'youtube' this.videoType === 'youtube'
) { ) {
if (availablePlaybackRates.length === 1 && !this.isTouch) { if (availablePlaybackRates.length === 1 && !this.isTouch) {
...@@ -568,7 +568,7 @@ function (HTML5Video, Resizer) { ...@@ -568,7 +568,7 @@ function (HTML5Video, Resizer) {
_restartUsingFlash(this); _restartUsingFlash(this);
} else if (availablePlaybackRates.length > 1) { } else if (availablePlaybackRates.length > 1) {
this.currentPlayerMode = 'html5'; this.setPlayerMode('html5');
// We need to synchronize available frame rates with the ones // We need to synchronize available frame rates with the ones
// that the user specified. // that the user specified.
...@@ -607,7 +607,7 @@ function (HTML5Video, Resizer) { ...@@ -607,7 +607,7 @@ function (HTML5Video, Resizer) {
this.trigger('videoSpeedControl.setSpeed', this.speed); this.trigger('videoSpeedControl.setSpeed', this.speed);
} }
if (this.currentPlayerMode === 'html5') { if (this.isHtml5Mode()) {
this.videoPlayer.player.setPlaybackRate(this.speed); this.videoPlayer.player.setPlaybackRate(this.speed);
} }
......
...@@ -234,6 +234,7 @@ function (Sjson, AsyncProcess) { ...@@ -234,6 +234,7 @@ function (Sjson, AsyncProcess) {
}; };
} }
state.el.removeClass('is-captions-rendered');
// Fetch the captions file. If no file was specified, or if an error // Fetch the captions file. If no file was specified, or if an error
// occurred, then we hide the captions panel, and the "CC" button // occurred, then we hide the captions panel, and the "CC" button
this.fetchXHR = $.ajaxWithPrefix({ this.fetchXHR = $.ajaxWithPrefix({
...@@ -447,9 +448,9 @@ function (Sjson, AsyncProcess) { ...@@ -447,9 +448,9 @@ function (Sjson, AsyncProcess) {
// outline has to be drawn (tabbing) or not (mouse click). // outline has to be drawn (tabbing) or not (mouse click).
self.isMouseFocus = false; self.isMouseFocus = false;
self.rendered = true; self.rendered = true;
self.state.el.addClass('is-captions-rendered');
}; };
this.rendered = false; this.rendered = false;
this.subtitlesEl.empty(); this.subtitlesEl.empty();
this.setSubtitlesHeight(); this.setSubtitlesHeight();
......
...@@ -10,7 +10,6 @@ in-browser HTML5 video method (when in HTML5 mode). ...@@ -10,7 +10,6 @@ in-browser HTML5 video method (when in HTML5 mode).
- Navigational subtitles can be disabled altogether via an attribute - Navigational subtitles can be disabled altogether via an attribute
in XML. in XML.
""" """
import os
import json import json
import logging import logging
from operator import itemgetter from operator import itemgetter
...@@ -36,8 +35,6 @@ from .video_utils import create_youtube_string ...@@ -36,8 +35,6 @@ from .video_utils import create_youtube_string
from .video_xfields import VideoFields from .video_xfields import VideoFields
from .video_handlers import VideoStudentViewHandlers, VideoStudioViewHandlers from .video_handlers import VideoStudentViewHandlers, VideoStudioViewHandlers
from xmodule.modulestore.inheritance import InheritanceKeyValueStore
from xblock.runtime import KvsFieldData
from urlparse import urlparse from urlparse import urlparse
def get_ext(filename): def get_ext(filename):
......
...@@ -310,3 +310,34 @@ Feature: LMS Video component ...@@ -310,3 +310,34 @@ Feature: LMS Video component
When I open video "D" When I open video "D"
Then the video has rendered in "HTML5" mode Then the video has rendered in "HTML5" mode
And the video does not show the captions And the video does not show the captions
# 27
Scenario: Transcripts are available on different speeds of Flash mode
Given I am registered for the course "test_course"
And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
And it has a video in "Flash" mode
Then the video has rendered in "Flash" mode
And I make sure captions are opened
And I see "Hi, welcome to Edx." text in the captions
Then I select the "1.50" speed
And I see "Hi, welcome to Edx." text in the captions
Then I select the "0.75" speed
And I see "Hi, welcome to Edx." text in the captions
Then I select the "1.25" speed
And I see "Hi, welcome to Edx." text in the captions
# 28
Scenario: Elapsed time calculates correctly on different speeds of Flash mode
Given I am registered for the course "test_course"
And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
And it has a video in "Flash" mode
And I make sure captions are opened
Then I select the "1.50" speed
And I click video button "pause"
And I click on caption line "4", video module shows elapsed time "7"
Then I select the "0.75" speed
And I click video button "pause"
And I click on caption line "3", video module shows elapsed time "9"
Then I select the "1.25" speed
And I click video button "pause"
And I click on caption line "2", video module shows elapsed time "4"
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# pylint: disable=C0111 # pylint: disable=C0111
from lettuce import world, step, before from lettuce import world, step, before, after
import json import json
import os import os
import time import time
...@@ -26,6 +26,13 @@ HTML5_SOURCES = [ ...@@ -26,6 +26,13 @@ HTML5_SOURCES = [
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.ogv', 'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.ogv',
] ]
FLASH_SOURCES = {
'youtube_id_1_0': 'OEoXaMPEzfM',
'youtube_id_0_75': 'JMD_ifUUfsU',
'youtube_id_1_25': 'AKqURZnYqpk',
'youtube_id_1_5': 'DYpADpL7jAY',
}
HTML5_SOURCES_INCORRECT = [ HTML5_SOURCES_INCORRECT = [
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.mp99', 'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.mp99',
] ]
...@@ -52,6 +59,11 @@ def setUp(scenario): ...@@ -52,6 +59,11 @@ def setUp(scenario):
world.video_sequences = {} world.video_sequences = {}
@after.each_scenario
def tearDown(scenario):
world.browser.cookies.delete('edX_video_player_mode')
class RequestHandlerWithSessionId(object): class RequestHandlerWithSessionId(object):
def get(self, url): def get(self, url):
""" """
...@@ -98,19 +110,6 @@ def get_metadata(parent_location, player_mode, data, display_name='Video'): ...@@ -98,19 +110,6 @@ def get_metadata(parent_location, player_mode, data, display_name='Video'):
'metadata': {}, 'metadata': {},
} }
if data:
conversions = {
'transcripts': json.loads,
'download_track': json.loads,
'download_video': json.loads,
}
for key in data:
if key in conversions:
data[key] = conversions[key](data[key])
kwargs['metadata'].update(data)
if player_mode == 'html5': if player_mode == 'html5':
kwargs['metadata'].update({ kwargs['metadata'].update({
'youtube_id_1_0': '', 'youtube_id_1_0': '',
...@@ -136,6 +135,23 @@ def get_metadata(parent_location, player_mode, data, display_name='Video'): ...@@ -136,6 +135,23 @@ def get_metadata(parent_location, player_mode, data, display_name='Video'):
'html5_sources': HTML5_SOURCES_INCORRECT 'html5_sources': HTML5_SOURCES_INCORRECT
}) })
if player_mode == 'flash':
kwargs['metadata'].update(FLASH_SOURCES)
world.browser.cookies.add({'edX_video_player_mode': 'flash'})
if data:
conversions = {
'transcripts': json.loads,
'download_track': json.loads,
'download_video': json.loads,
}
for key in data:
if key in conversions:
data[key] = conversions[key](data[key])
kwargs['metadata'].update(data)
return kwargs return kwargs
...@@ -251,6 +267,14 @@ def duration(): ...@@ -251,6 +267,14 @@ def duration():
return duration return duration
def elapsed_time():
"""
Elapsed time of the video, in seconds.
"""
elapsed_time, duration = video_time()
return elapsed_time
def video_time(): def video_time():
""" """
Return a tuple `(elapsed_time, duration)`, each in seconds. Return a tuple `(elapsed_time, duration)`, each in seconds.
...@@ -273,6 +297,11 @@ def parse_time_str(time_str): ...@@ -273,6 +297,11 @@ def parse_time_str(time_str):
return time_obj.tm_min * 60 + time_obj.tm_sec return time_obj.tm_min * 60 + time_obj.tm_sec
def find_caption_line_by_data_index(index):
SELECTOR = ".subtitles > li[data-index='{index}']".format(index=index)
return world.css_find(SELECTOR).first
@step('youtube stub server (.*) YouTube API') @step('youtube stub server (.*) YouTube API')
def configure_youtube_api(_step, action): def configure_youtube_api(_step, action):
action=action.strip() action=action.strip()
...@@ -349,7 +378,8 @@ def set_youtube_response_timeout(_step, time): ...@@ -349,7 +378,8 @@ def set_youtube_response_timeout(_step, time):
def video_is_rendered(_step, mode): def video_is_rendered(_step, mode):
modes = { modes = {
'html5': 'video', 'html5': 'video',
'youtube': 'iframe' 'youtube': 'iframe',
'flash': 'iframe',
} }
html_tag = modes[mode.lower()] html_tag = modes[mode.lower()]
assert world.css_find('.video {0}'.format(html_tag)).first assert world.css_find('.video {0}'.format(html_tag)).first
...@@ -360,7 +390,8 @@ def video_is_rendered(_step, mode): ...@@ -360,7 +390,8 @@ def video_is_rendered(_step, mode):
def videos_are_rendered(_step, mode): def videos_are_rendered(_step, mode):
modes = { modes = {
'html5': 'video', 'html5': 'video',
'youtube': 'iframe' 'youtube': 'iframe',
'flash': 'iframe',
} }
html_tag = modes[mode.lower()] html_tag = modes[mode.lower()]
...@@ -423,6 +454,7 @@ def i_see_menu(_step, menu): ...@@ -423,6 +454,7 @@ def i_see_menu(_step, menu):
@step('I see "([^"]*)" text in the captions$') @step('I see "([^"]*)" text in the captions$')
def check_text_in_the_captions(_step, text): def check_text_in_the_captions(_step, text):
world.wait_for_present('.video.is-captions-rendered')
world.wait_for(lambda _: world.css_text('.subtitles')) world.wait_for(lambda _: world.css_text('.subtitles'))
actual_text = world.css_text('.subtitles') actual_text = world.css_text('.subtitles')
assert (text in actual_text) assert (text in actual_text)
...@@ -430,6 +462,7 @@ def check_text_in_the_captions(_step, text): ...@@ -430,6 +462,7 @@ def check_text_in_the_captions(_step, text):
@step('I see text in the captions:') @step('I see text in the captions:')
def check_captions(_step): def check_captions(_step):
world.wait_for_present('.video.is-captions-rendered')
for index, video in enumerate(_step.hashes): for index, video in enumerate(_step.hashes):
assert (video.get('text') in world.css_text('.subtitles', index=index)) assert (video.get('text') in world.css_text('.subtitles', index=index))
...@@ -439,12 +472,12 @@ def select_language(_step, code): ...@@ -439,12 +472,12 @@ def select_language(_step, code):
# Make sure that all ajax requests that affects the language menu are finished. # Make sure that all ajax requests that affects the language menu are finished.
# For example, request to get new translation etc. # For example, request to get new translation etc.
world.wait_for_ajax_complete() world.wait_for_ajax_complete()
selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format( selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format(
code=code code=code
) )
world.css_find(VIDEO_BUTTONS["CC"])[0].mouse_over() world.css_find(VIDEO_BUTTONS["CC"])[0].mouse_over()
world.wait_for_present('.lang.open')
world.css_click(selector) world.css_click(selector)
assert world.css_has_class(selector, 'active') assert world.css_has_class(selector, 'active')
...@@ -454,6 +487,7 @@ def select_language(_step, code): ...@@ -454,6 +487,7 @@ def select_language(_step, code):
# For example, request to get new translation etc. # For example, request to get new translation etc.
world.wait_for_ajax_complete() world.wait_for_ajax_complete()
world.wait_for_visible('.subtitles') world.wait_for_visible('.subtitles')
world.wait_for_present('.video.is-captions-rendered')
@step('I click video button "([^"]*)"$') @step('I click video button "([^"]*)"$')
...@@ -472,10 +506,12 @@ def start_playing_video_from_n_seconds(_step, position): ...@@ -472,10 +506,12 @@ def start_playing_video_from_n_seconds(_step, position):
@step('I see duration "([^"]*)"$') @step('I see duration "([^"]*)"$')
def i_see_duration(_step, position): def i_see_duration(_step, position):
world.wait_for( world.wait_for(
func=lambda _: duration() == parse_time_str(position), func=lambda _: duration() > 0,
timeout=30 timeout=30
) )
assert duration() == parse_time_str(position)
@step('I seek video to "([^"]*)" seconds$') @step('I seek video to "([^"]*)" seconds$')
def seek_video_to_n_seconds(_step, seconds): def seek_video_to_n_seconds(_step, seconds):
...@@ -507,14 +543,11 @@ def video_alignment(_step, transcript_visibility): ...@@ -507,14 +543,11 @@ def video_alignment(_step, transcript_visibility):
set_window_dimensions(300, 600) set_window_dimensions(300, 600)
real, expected = get_all_dimensions() real, expected = get_all_dimensions()
width = round(100 * real['width']/expected['width']) == wrapper_width width = round(100 * real['width']/expected['width']) == wrapper_width
set_window_dimensions(600, 300) set_window_dimensions(600, 300)
real, expected = get_all_dimensions() real, expected = get_all_dimensions()
height = abs(expected['height'] - real['height']) <= 5 height = abs(expected['height'] - real['height']) <= 5
# Restore initial window size # Restore initial window size
set_window_dimensions(initial['width'], initial['height']) set_window_dimensions(initial['width'], initial['height'])
...@@ -569,3 +602,12 @@ def shows_captions(_step, show_captions): ...@@ -569,3 +602,12 @@ def shows_captions(_step, show_captions):
assert world.is_css_present('div.video.closed') assert world.is_css_present('div.video.closed')
else: else:
assert world.is_css_not_present('div.video.closed') assert world.is_css_not_present('div.video.closed')
@step('I click on caption line "([^"]*)", video module shows elapsed time "([^"]*)"$')
def click_on_the_caption(_step, index, expected_time):
world.wait_for_present('.video.is-captions-rendered')
find_caption_line_by_data_index(int(index)).click()
actual_time = elapsed_time()
assert int(expected_time) == actual_time
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